This commit is contained in:
root@pico committed 2015-05-01 21:20:47 +02:00
1 parent 70d2335bba
commit 7428b67da5
1086 files changed
+94145 -59082

No files matched your search

@@ -1,416 +1,429 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Modified (Reduced) TextStatistics Class
*
* Mostly removed functionality that isn't needed within the WordPress SEO plugin.
*
* @link http://code.google.com/p/php-text-statistics/
* @link https://github.com/DaveChild/Text-Statistics (new repo location)
* @license http://www.opensource.org/licenses/bsd-license.php New BSD license
*
* @todo [JRF => whomever] Research if a class/library can be found which will offer
* this functionality to a broader scope of languages/charsets.
* Now basically limited to English.
*/
class Yoast_TextStatistics {
if ( ! class_exists( 'Yoast_TextStatistics' ) ) {
/**
* Modified (Reduced) TextStatistics Class
*
* Mostly removed functionality that isn't needed within the WordPress SEO plugin.
*
* @link http://code.google.com/p/php-text-statistics/
* @link https://github.com/DaveChild/Text-Statistics (new repo location)
* @license http://www.opensource.org/licenses/bsd-license.php New BSD license
*
* @todo [JRF => whomever] Research if a class/library can be found which will offer
* this functionality to a broader scope of languages/charsets.
* Now basically limited to English.
* @var string $strEncoding Used to hold character encoding to be used by object, if set
*/
class Yoast_TextStatistics {
protected $strEncoding = '';
/**
* @var string $strEncoding Used to hold character encoding to be used by object, if set
*/
protected $strEncoding = '';
/**
* @var string $blnMbstring Efficiency: Is the MB String extension loaded ?
*/
protected $blnMbstring = true;
/**
* @var string $blnMbstring Efficiency: Is the MB String extension loaded ?
*/
protected $blnMbstring = true;
/**
* @var bool $normalize Should the result be normalized ?
*/
public $normalize = true;
/**
* @var bool $normalize Should the result be normalized ?
*/
public $normalize = true;
/**
* Constructor.
*
* @param string $strEncoding Optional character encoding.
*/
public function __construct( $strEncoding = '' ) {
if ( $strEncoding <> '' ) {
// Encoding is given. Use it!
$this->strEncoding = $strEncoding;
}
$this->blnMbstring = extension_loaded( 'mbstring' );
/**
* Constructor.
*
* @param string $strEncoding Optional character encoding.
*/
public function __construct( $strEncoding = '' ) {
if ( $strEncoding <> '' ) {
// Encoding is given. Use it!
$this->strEncoding = $strEncoding;
}
$this->blnMbstring = extension_loaded( 'mbstring' );
}
/**
* Gives the Flesch-Kincaid Reading Ease of text entered rounded to one digit
*
* @param string $strText Text to be checked
*
* @return int|float
*/
public function flesch_kincaid_reading_ease( $strText ) {
$strText = $this->clean_text( $strText );
$score = WPSEO_Utils::calc( WPSEO_Utils::calc( 206.835, '-', WPSEO_Utils::calc( 1.015, '*', $this->average_words_per_sentence( $strText ) ) ), '-', WPSEO_Utils::calc( 84.6, '*', $this->average_syllables_per_word( $strText ) ) );
return $this->normalize_score( $score, 0, 100 );
}
/**
* Gives string length.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function text_length( $strText ) {
if ( ! $this->blnMbstring ) {
return strlen( $strText );
}
/**
* Gives the Flesch-Kincaid Reading Ease of text entered rounded to one digit
*
* @param string $strText Text to be checked
* @return int|float
*/
public function flesch_kincaid_reading_ease( $strText ) {
$strText = $this->clean_text( $strText );
$score = wpseo_calc( wpseo_calc( 206.835, '-', wpseo_calc( 1.015, '*', $this->average_words_per_sentence( $strText ) ) ), '-', wpseo_calc( 84.6, '*', $this->average_syllables_per_word( $strText ) ) );
return $this->normalize_score( $score, 0, 100 );
try {
if ( $this->strEncoding == '' ) {
$intTextLength = mb_strlen( $strText );
}
else {
$intTextLength = mb_strlen( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$intTextLength = strlen( $strText );
}
/**
* Gives string length.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function text_length( $strText ) {
if ( ! $this->blnMbstring ) {
return strlen( $strText );
}
return $intTextLength;
}
try {
if ( $this->strEncoding == '' ) {
$intTextLength = mb_strlen( $strText );
} else {
$intTextLength = mb_strlen( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$intTextLength = strlen( $strText );
}
/**
* Gives letter count (ignores all non-letters). Tries mb_strlen and if that fails uses regular strlen.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function letter_count( $strText ) {
$strText = $this->clean_text( $strText ); // To clear out newlines etc
$strText = preg_replace( '`[^A-Za-z]+`', '', $strText );
return $intTextLength;
if ( ! $this->blnMbstring ) {
return strlen( $strText );
}
/**
* Gives letter count (ignores all non-letters). Tries mb_strlen and if that fails uses regular strlen.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function letter_count( $strText ) {
$strText = $this->clean_text( $strText ); // To clear out newlines etc
$strText = preg_replace( '`[^A-Za-z]+`', '', $strText );
if ( ! $this->blnMbstring ) {
return strlen( $strText );
try {
if ( $this->strEncoding == '' ) {
$intTextLength = mb_strlen( $strText );
}
try {
if ( $this->strEncoding == '' ) {
$intTextLength = mb_strlen( $strText );
} else {
$intTextLength = mb_strlen( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$intTextLength = strlen( $strText );
else {
$intTextLength = mb_strlen( $strText, $this->strEncoding );
}
return $intTextLength;
} catch ( Exception $e ) {
$intTextLength = strlen( $strText );
}
/**
* Trims, removes line breaks, multiple spaces and generally cleans text before processing.
*
* @param string $strText Text to be transformed
* @return string
*/
protected function clean_text( $strText ) {
static $clean = array();
return $intTextLength;
}
$key = sha1( $strText );
/**
* Trims, removes line breaks, multiple spaces and generally cleans text before processing.
*
* @param string $strText Text to be transformed
*
* @return string
*/
protected function clean_text( $strText ) {
static $clean = array();
if ( isset( $clean[ $key ] ) ) {
return $clean[ $key ];
}
$key = sha1( $strText );
// all these tags should be preceeded by a full stop.
$fullStopTags = array( 'li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dd' );
foreach ( $fullStopTags as $tag ) {
$strText = str_ireplace( '</' . $tag . '>', '.', $strText );
}
$strText = strip_tags( $strText );
$strText = preg_replace( '`[",:;\(\)-]`', ' ', $strText ); // Replace commas, hyphens etc (count them as spaces)
$strText = preg_replace( '`[\.!?]`', '.', $strText ); // Unify terminators
$strText = trim( $strText ) . '.'; // Add final terminator, just in case it's missing.
$strText = preg_replace( '`[ ]*(\n|\r\n|\r)[ ]*`', ' ', $strText ); // Replace new lines with spaces
$strText = preg_replace( '`([\.])[\. ]+`', '$1', $strText ); // Check for duplicated terminators
$strText = trim( preg_replace( '`[ ]*([\.])`', '$1 ', $strText ) ); // Pad sentence terminators
$strText = preg_replace( '` [0-9]+ `', ' ', ' ' . $strText . ' ' ); // Remove "words" comprised only of numbers
$strText = preg_replace( '`[ ]+`', ' ', $strText ); // Remove multiple spaces
$strText = preg_replace_callback( '`\. [^ ]+?`', create_function( '$matches', 'return strtolower( $matches[0] );' ), $strText ); // Lower case all words following terminators (for gunning fog score)
$strText = trim( $strText );
// Cache it and return
$clean[ $key ] = $strText;
return $strText;
if ( isset( $clean[ $key ] ) ) {
return $clean[ $key ];
}
/**
* Converts string to lower case. Tries mb_strtolower and if that fails uses regular strtolower.
*
* @param string $strText Text to be transformed
* @return string
*/
protected function lower_case( $strText ) {
// all these tags should be preceeded by a full stop.
$fullStopTags = array( 'li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dd' );
foreach ( $fullStopTags as $tag ) {
$strText = str_ireplace( '</' . $tag . '>', '.', $strText );
}
$strText = strip_tags( $strText );
$strText = preg_replace( '`[",:;\(\)-]`', ' ', $strText ); // Replace commas, hyphens etc (count them as spaces)
$strText = preg_replace( '`[\.!?]`', '.', $strText ); // Unify terminators
$strText = trim( $strText ) . '.'; // Add final terminator, just in case it's missing.
$strText = preg_replace( '`[ ]*(\n|\r\n|\r)[ ]*`', ' ', $strText ); // Replace new lines with spaces
$strText = preg_replace( '`([\.])[\. ]+`', '$1', $strText ); // Check for duplicated terminators
$strText = trim( preg_replace( '`[ ]*([\.])`', '$1 ', $strText ) ); // Pad sentence terminators
$strText = preg_replace( '` [0-9]+ `', ' ', ' ' . $strText . ' ' ); // Remove "words" comprised only of numbers
$strText = preg_replace( '`[ ]+`', ' ', $strText ); // Remove multiple spaces
$strText = preg_replace_callback( '`\. [^ ]+?`', create_function( '$matches', 'return strtolower( $matches[0] );' ), $strText ); // Lower case all words following terminators (for gunning fog score)
if ( ! $this->blnMbstring ) {
return strtolower( $strText );
}
$strText = trim( $strText );
try {
if ( $this->strEncoding == '' ) {
$strLowerCaseText = mb_strtolower( $strText );
} else {
$strLowerCaseText = mb_strtolower( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$strLowerCaseText = strtolower( $strText );
}
// Cache it and return
$clean[ $key ] = $strText;
return $strLowerCaseText;
return $strText;
}
/**
* Converts string to lower case. Tries mb_strtolower and if that fails uses regular strtolower.
*
* @param string $strText Text to be transformed
*
* @return string
*/
protected function lower_case( $strText ) {
if ( ! $this->blnMbstring ) {
return strtolower( $strText );
}
/**
* Converts string to upper case. Tries mb_strtoupper and if that fails uses regular strtoupper.
*
* @param string $strText Text to be transformed
* @return string
*/
protected function upper_case( $strText ) {
if ( ! $this->blnMbstring ) {
return strtoupper( $strText );
try {
if ( $this->strEncoding == '' ) {
$strLowerCaseText = mb_strtolower( $strText );
}
try {
if ( $this->strEncoding == '' ) {
$strUpperCaseText = mb_strtoupper( $strText );
} else {
$strUpperCaseText = mb_strtoupper( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$strUpperCaseText = strtoupper( $strText );
else {
$strLowerCaseText = mb_strtolower( $strText, $this->strEncoding );
}
return $strUpperCaseText;
} catch ( Exception $e ) {
$strLowerCaseText = strtolower( $strText );
}
/**
* Returns sentence count for text.
*
* @param string $strText Text to be measured
* @return int
*/
public function sentence_count( $strText ) {
if ( strlen( trim( $strText ) ) == 0 ) {
return 0;
}
return $strLowerCaseText;
}
$strText = $this->clean_text( $strText );
// Will be tripped up by "Mr." or "U.K.". Not a major concern at this point.
// [JRF] Will also be tripped up by ... or ?!
// @todo [JRF => whomever] May be replace with something along the lines of this - will at least provide better count in ... and ?! situations:
// $intSentences = max( 1, preg_match_all( '`[^\.!?]+[\.!?]+([\s]+|$)`u', $strText, $matches ) ); [/JRF]
$intSentences = max( 1, $this->text_length( preg_replace( '`[^\.!?]`', '', $strText ) ) );
return $intSentences;
/**
* Converts string to upper case. Tries mb_strtoupper and if that fails uses regular strtoupper.
*
* @param string $strText Text to be transformed
*
* @return string
*/
protected function upper_case( $strText ) {
if ( ! $this->blnMbstring ) {
return strtoupper( $strText );
}
/**
* Returns word count for text.
*
* @param string $strText Text to be measured
* @return int
*/
public function word_count( $strText ) {
if ( strlen( trim( $strText ) ) == 0 ) {
return 0;
try {
if ( $this->strEncoding == '' ) {
$strUpperCaseText = mb_strtoupper( $strText );
}
$strText = $this->clean_text( $strText );
// Will be tripped by em dashes with spaces either side, among other similar characters
$intWords = 1 + $this->text_length( preg_replace( '`[^ ]`', '', $strText ) ); // Space count + 1 is word count
return $intWords;
else {
$strUpperCaseText = mb_strtoupper( $strText, $this->strEncoding );
}
} catch ( Exception $e ) {
$strUpperCaseText = strtoupper( $strText );
}
/**
* Returns average words per sentence for text.
*
* @param string $strText Text to be measured
* @return int|float
*/
public function average_words_per_sentence( $strText ) {
$strText = $this->clean_text( $strText );
$intSentenceCount = $this->sentence_count( $strText );
$intWordCount = $this->word_count( $strText );
return ( wpseo_calc( $intWordCount, '/', $intSentenceCount ) );
return $strUpperCaseText;
}
/**
* Returns sentence count for text.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function sentence_count( $strText ) {
if ( strlen( trim( $strText ) ) == 0 ) {
return 0;
}
/**
* Returns average syllables per word for text.
*
* @param string $strText Text to be measured
* @return int|float
*/
public function average_syllables_per_word( $strText ) {
$strText = $this->clean_text( $strText );
$intSyllableCount = 0;
$intWordCount = $this->word_count( $strText );
$arrWords = explode( ' ', $strText );
for ( $i = 0; $i < $intWordCount; $i++ ) {
$intSyllableCount += $this->syllable_count( $arrWords[ $i ] );
}
return ( wpseo_calc( $intSyllableCount, '/', $intWordCount ) );
$strText = $this->clean_text( $strText );
// Will be tripped up by "Mr." or "U.K.". Not a major concern at this point.
// [JRF] Will also be tripped up by ... or ?!
// @todo [JRF => whomever] May be replace with something along the lines of this - will at least provide better count in ... and ?! situations:
// $intSentences = max( 1, preg_match_all( '`[^\.!?]+[\.!?]+([\s]+|$)`u', $strText, $matches ) ); [/JRF]
$intSentences = max( 1, $this->text_length( preg_replace( '`[^\.!?]`', '', $strText ) ) );
return $intSentences;
}
/**
* Returns word count for text.
*
* @param string $strText Text to be measured
*
* @return int
*/
public function word_count( $strText ) {
if ( strlen( trim( $strText ) ) == 0 ) {
return 0;
}
/**
* Returns the number of syllables in the word.
* Based in part on Greg Fast's Perl module Lingua::EN::Syllables
*
* @param string $strWord Word to be measured
* @return int
*/
public function syllable_count( $strWord ) {
if ( strlen( trim( $strWord ) ) == 0 ) {
return 0;
}
$strText = $this->clean_text( $strText );
// Will be tripped by em dashes with spaces either side, among other similar characters
$intWords = ( 1 + $this->text_length( preg_replace( '`[^ ]`', '', $strText ) ) ); // Space count + 1 is word count
return $intWords;
}
// Should be no non-alpha characters
$strWord = preg_replace( '`[^A-Za-z]`', '', $strWord );
/**
* Returns average words per sentence for text.
*
* @param string $strText Text to be measured
*
* @return int|float
*/
public function average_words_per_sentence( $strText ) {
$strText = $this->clean_text( $strText );
$intSentenceCount = $this->sentence_count( $strText );
$intWordCount = $this->word_count( $strText );
$intSyllableCount = 0;
$strWord = $this->lower_case( $strWord );
return ( WPSEO_Utils::calc( $intWordCount, '/', $intSentenceCount ) );
}
// Specific common exceptions that don't follow the rule set below are handled individually
// Array of problem words (with word as key, syllable count as value)
$arrProblemWords = array(
'simile' => 3,
'forever' => 3,
'shoreline' => 2,
);
if ( isset( $arrProblemWords[ $strWord ] ) ) {
$intSyllableCount = $arrProblemWords[ $strWord ];
}
if ( $intSyllableCount > 0 ) {
return $intSyllableCount;
}
/**
* Returns average syllables per word for text.
*
* @param string $strText Text to be measured
*
* @return int|float
*/
public function average_syllables_per_word( $strText ) {
$strText = $this->clean_text( $strText );
$intSyllableCount = 0;
$intWordCount = $this->word_count( $strText );
$arrWords = explode( ' ', $strText );
for ( $i = 0; $i < $intWordCount; $i ++ ) {
$intSyllableCount += $this->syllable_count( $arrWords[ $i ] );
}
// These syllables would be counted as two but should be one
$arrSubSyllables = array(
'cial',
'tia',
'cius',
'cious',
'giu',
'ion',
'iou',
'sia$',
'[^aeiuoyt]{2,}ed$',
'.ely$',
'[cg]h?e[rsd]?$',
'rved?$',
'[aeiouy][dt]es?$',
'[aeiouy][^aeiouydt]e[rsd]?$',
// Sorts out deal, deign etc
'^[dr]e[aeiou][^aeiou]+$',
// Purse, hearse
'[aeiouy]rse$',
);
return ( WPSEO_Utils::calc( $intSyllableCount, '/', $intWordCount ) );
}
// These syllables would be counted as one but should be two
$arrAddSyllables = array(
'ia',
'riet',
'dien',
'iu',
'io',
'ii',
'[aeiouym]bl$',
'[aeiou]{3}',
'^mc',
'ism$',
'([^aeiouy])\1l$',
'[^l]lien',
'^coa[dglx].',
'[^gq]ua[^auieo]',
'dnt$',
'uity$',
'ie(r|st)$',
);
/**
* Returns the number of syllables in the word.
* Based in part on Greg Fast's Perl module Lingua::EN::Syllables
*
* @param string $strWord Word to be measured
*
* @return int
*/
public function syllable_count( $strWord ) {
if ( strlen( trim( $strWord ) ) == 0 ) {
return 0;
}
// Single syllable prefixes and suffixes
$arrPrefixSuffix = array(
'`^un`',
'`^fore`',
'`ly$`',
'`less$`',
'`ful$`',
'`ers?$`',
'`ings?$`',
);
// Should be no non-alpha characters
$strWord = preg_replace( '`[^A-Za-z]`', '', $strWord );
// Remove prefixes and suffixes and count how many were taken
$strWord = preg_replace( $arrPrefixSuffix, '', $strWord, -1, $intPrefixSuffixCount );
$intSyllableCount = 0;
$strWord = $this->lower_case( $strWord );
// Removed non-word characters from word
$strWord = preg_replace( '`[^a-z]`is', '', $strWord );
$arrWordParts = preg_split( '`[^aeiouy]+`', $strWord );
$intWordPartCount = 0;
foreach ( $arrWordParts as $strWordPart ) {
if ( $strWordPart <> '' ) {
$intWordPartCount++;
}
}
// Some syllables do not follow normal rules - check for them
// Thanks to Joe Kovar for correcting a bug in the following lines
$intSyllableCount = $intWordPartCount + $intPrefixSuffixCount;
foreach ( $arrSubSyllables as $strSyllable ) {
$intSyllableCount -= preg_match( '`' . $strSyllable . '`', $strWord );
}
foreach ( $arrAddSyllables as $strSyllable ) {
$intSyllableCount += preg_match( '`' . $strSyllable . '`', $strWord );
}
$intSyllableCount = ( $intSyllableCount == 0 ) ? 1 : $intSyllableCount;
// Specific common exceptions that don't follow the rule set below are handled individually
// Array of problem words (with word as key, syllable count as value)
$arrProblemWords = array(
'simile' => 3,
'forever' => 3,
'shoreline' => 2,
);
if ( isset( $arrProblemWords[ $strWord ] ) ) {
$intSyllableCount = $arrProblemWords[ $strWord ];
}
if ( $intSyllableCount > 0 ) {
return $intSyllableCount;
}
/**
* Normalizes score according to min & max allowed. If score larger
* than max, max is returned. If score less than min, min is returned.
* Also rounds result to specified precision.
* Thanks to github.com/lvil.
*
* @param int|float $score Initial score
* @param int $min Minimum score allowed
* @param int $max Maximum score allowed
* @return int|float
*/
public function normalize_score( $score, $min, $max, $dps = 1 ) {
$score = wpseo_calc( $score, '+', 0, true, $dps ); // Round
if ( ! $this->normalize ) {
return $score;
}
// These syllables would be counted as two but should be one
$arrSubSyllables = array(
'cial',
'tia',
'cius',
'cious',
'giu',
'ion',
'iou',
'sia$',
'[^aeiuoyt]{2,}ed$',
'.ely$',
'[cg]h?e[rsd]?$',
'rved?$',
'[aeiouy][dt]es?$',
'[aeiouy][^aeiouydt]e[rsd]?$',
// Sorts out deal, deign etc
'^[dr]e[aeiou][^aeiou]+$',
// Purse, hearse
'[aeiouy]rse$',
);
if ( $score > $max ) {
$score = $max;
} elseif ( $score < $min ) {
$score = $min;
}
// These syllables would be counted as one but should be two
$arrAddSyllables = array(
'ia',
'riet',
'dien',
'iu',
'io',
'ii',
'[aeiouym]bl$',
'[aeiou]{3}',
'^mc',
'ism$',
'([^aeiouy])\1l$',
'[^l]lien',
'^coa[dglx].',
'[^gq]ua[^auieo]',
'dnt$',
'uity$',
'ie(r|st)$',
);
// Single syllable prefixes and suffixes
$arrPrefixSuffix = array(
'`^un`',
'`^fore`',
'`ly$`',
'`less$`',
'`ful$`',
'`ers?$`',
'`ings?$`',
);
// Remove prefixes and suffixes and count how many were taken
$strWord = preg_replace( $arrPrefixSuffix, '', $strWord, - 1, $intPrefixSuffixCount );
// Removed non-word characters from word
$strWord = preg_replace( '`[^a-z]`is', '', $strWord );
$arrWordParts = preg_split( '`[^aeiouy]+`', $strWord );
$intWordPartCount = 0;
foreach ( $arrWordParts as $strWordPart ) {
if ( $strWordPart <> '' ) {
$intWordPartCount ++;
}
}
// Some syllables do not follow normal rules - check for them
// Thanks to Joe Kovar for correcting a bug in the following lines
$intSyllableCount = ( $intWordPartCount + $intPrefixSuffixCount );
foreach ( $arrSubSyllables as $strSyllable ) {
$intSyllableCount -= preg_match( '`' . $strSyllable . '`', $strWord );
}
foreach ( $arrAddSyllables as $strSyllable ) {
$intSyllableCount += preg_match( '`' . $strSyllable . '`', $strWord );
}
$intSyllableCount = ( $intSyllableCount == 0 ) ? 1 : $intSyllableCount;
return $intSyllableCount;
}
/**
* Normalizes score according to min & max allowed. If score larger
* than max, max is returned. If score less than min, min is returned.
* Also rounds result to specified precision.
* Thanks to github.com/lvil.
*
* @param int|float $score Initial score
* @param int $min Minimum score allowed
* @param int $max Maximum score allowed
* @param int $dps Round to # decimals
*
* @return int|float
*/
public function normalize_score( $score, $min, $max, $dps = 1 ) {
$score = WPSEO_Utils::calc( $score, '+', 0, true, $dps ); // Round
if ( ! $this->normalize ) {
return $score;
}
} /* End of class */
} /* End of class-exists wrapper */
if ( $score > $max ) {
$score = $max;
}
elseif ( $score < $min ) {
$score = $min;
}
return $score;
}
} /* End of class */
+111 -87
View File
@@ -1,6 +1,6 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,6 +9,20 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
/**
* @todo this whole thing should probably be a proper class.
*/
/**
* Convenience function to JSON encode and echo resuls and then die
*
* @param array $results
*/
function wpseo_ajax_json_echo_die( $results ) {
echo json_encode( $results );
die();
}
/**
* Function used from AJAX calls, takes it variables from $_POST, dies on exit.
*/
@@ -19,7 +33,7 @@ function wpseo_set_option() {
check_ajax_referer( 'wpseo-setoption' );
$option = sanitize_text_field( $_POST['option'] );
$option = sanitize_text_field( WPSEO_Utils::filter_input( INPUT_POST, 'option' ) );
if ( $option !== 'page_comments' ) {
die( '-1' );
}
@@ -41,7 +55,7 @@ function wpseo_set_ignore() {
check_ajax_referer( 'wpseo-ignore' );
$options = get_option( 'wpseo' );
$ignore_key = sanitize_text_field( $_POST['option'] );
$ignore_key = sanitize_text_field( WPSEO_Utils::filter_input( INPUT_POST, 'option' ) );
$options[ 'ignore_' . $ignore_key ] = true;
update_option( 'wpseo', $options );
die( '1' );
@@ -70,7 +84,7 @@ function wpseo_kill_blocking_files() {
}
else {
unset( $options['blocking_files'][ $k ] );
$files_removed++;
$files_removed ++;
}
}
if ( $files_removed > 0 ) {
@@ -90,7 +104,7 @@ add_action( 'wp_ajax_wpseo_kill_blocking_files', 'wpseo_kill_blocking_files' );
function wpseo_get_suggest() {
check_ajax_referer( 'wpseo-get-suggest' );
$term = urlencode( $_GET['term'] );
$term = urlencode( WPSEO_Utils::filter_input( INPUT_GET, 'term' ) );
$result = wp_remote_get( 'https://www.google.com/complete/search?output=toolbar&q=' . $term );
$return_arr = array();
@@ -104,8 +118,7 @@ function wpseo_get_suggest() {
}
}
}
echo json_encode( $return_arr );
die();
wpseo_ajax_json_echo_die( $return_arr );
}
add_action( 'wp_ajax_wpseo_get_suggest', 'wpseo_get_suggest' );
@@ -114,11 +127,12 @@ add_action( 'wp_ajax_wpseo_get_suggest', 'wpseo_get_suggest' );
* Used in the editor to replace vars for the snippet preview
*/
function wpseo_ajax_replace_vars() {
global $post;
check_ajax_referer( 'wpseo-replace-vars' );
$post = get_post( $_POST['post_id'] );
$post = get_post( intval( WPSEO_Utils::filter_input( INPUT_POST, 'post_id' ) ) );
$omit = array( 'excerpt', 'excerpt_only', 'title' );
echo wpseo_replace_vars( stripslashes( $_POST['string'] ), $post, $omit );
echo wpseo_replace_vars( stripslashes( WPSEO_Utils::filter_input( INPUT_POST, 'string' ) ), $post, $omit );
die;
}
@@ -128,40 +142,54 @@ add_action( 'wp_ajax_wpseo_replace_vars', 'wpseo_ajax_replace_vars' );
* Save an individual SEO title from the Bulk Editor.
*/
function wpseo_save_title() {
check_ajax_referer( 'wpseo-bulk-editor' );
$new_title = $_POST['new_value'];
$id = intval( $_POST['wpseo_post_id'] );
$original_title = $_POST['existing_value'];
$results = wpseo_upsert_new_title( $id, $new_title, $original_title );
echo json_encode( $results );
die();
wpseo_save_what( 'title' );
}
add_action( 'wp_ajax_wpseo_save_title', 'wpseo_save_title' );
/**
* Helper function for updating an existing seo title or create a new one
* if it doesn't already exist.
* Save an individual meta description from the Bulk Editor.
*/
function wpseo_upsert_new_title( $post_id, $new_title, $original_title ) {
function wpseo_save_description() {
wpseo_save_what( 'metadesc' );
}
$meta_key = WPSEO_Meta::$meta_prefix . 'title';
$return_key = 'title';
return wpseo_upsert_meta( $post_id, $new_title, $original_title, $meta_key, $return_key );
add_action( 'wp_ajax_wpseo_save_metadesc', 'wpseo_save_description' );
/**
* Save titles & descriptions
*
* @param string $what
*/
function wpseo_save_what( $what ) {
check_ajax_referer( 'wpseo-bulk-editor' );
$new = WPSEO_Utils::filter_input( INPUT_POST, 'new_value' );
$post_id = intval( WPSEO_Utils::filter_input( INPUT_POST, 'wpseo_post_id' ) );
$original = WPSEO_Utils::filter_input( INPUT_POST, 'existing_value' );
$results = wpseo_upsert_new( $what, $post_id, $new, $original );
wpseo_ajax_json_echo_die( $results );
}
/**
* Helper function to update a post's meta data, returning relevant information
* about the information updated and the results or the meta update.
*
* @param int $post_id
* @param string $new_meta_value
* @param string $orig_meta_value
* @param string $meta_key
* @param string $return_key
*
* @return string
*/
function wpseo_upsert_meta( $post_id, $new_meta_value, $orig_meta_value, $meta_key, $return_key ) {
$post_id = intval( $post_id );
$sanitized_new_meta_value = wp_strip_all_tags( $new_meta_value );
$orig_meta_value = wp_strip_all_tags( $orig_meta_value );
$post_id = intval( $post_id );
$sanitized_new_meta_value = wp_strip_all_tags( $new_meta_value );
$orig_meta_value = wp_strip_all_tags( $orig_meta_value );
$upsert_results = array(
'status' => 'success',
@@ -224,73 +252,69 @@ function wpseo_upsert_meta( $post_id, $new_meta_value, $orig_meta_value, $meta_k
* Save all titles sent from the Bulk Editor.
*/
function wpseo_save_all_titles() {
check_ajax_referer( 'wpseo-bulk-editor' );
$new_titles = $_POST['items'];
$original_titles = $_POST['existing_items'];
$results = array();
if ( is_array( $new_titles ) && $new_titles !== array() ) {
foreach ( $new_titles as $id => $new_title ) {
$original_title = $original_titles[ $id ];
$results[] = wpseo_upsert_new_title( $id, $new_title, $original_title );
}
}
echo json_encode( $results );
die();
wpseo_save_all( 'title' );
}
add_action( 'wp_ajax_wpseo_save_all_titles', 'wpseo_save_all_titles' );
/**
* Save an individual meta description from the Bulk Editor.
*/
function wpseo_save_description() {
check_ajax_referer( 'wpseo-bulk-editor' );
$new_metadesc = $_POST['new_value'];
$id = intval( $_POST['wpseo_post_id'] );
$original_metadesc = $_POST['existing_value'];
$results = wpseo_upsert_new_description( $id, $new_metadesc, $original_metadesc );
echo json_encode( $results );
die();
}
add_action( 'wp_ajax_wpseo_save_metadesc', 'wpseo_save_description' );
/**
* Helper function to create or update a post's meta description.
*/
function wpseo_upsert_new_description( $post_id, $new_metadesc, $original_metadesc ) {
$meta_key = WPSEO_Meta::$meta_prefix . 'metadesc';
$return_key = 'metadesc';
return wpseo_upsert_meta( $post_id, $new_metadesc, $original_metadesc, $meta_key, $return_key );
}
/**
* Save all description sent from the Bulk Editor.
*/
function wpseo_save_all_descriptions() {
check_ajax_referer( 'wpseo-bulk-editor' );
$new_metadescs = $_POST['items'];
$original_metadescs = $_POST['existing_items'];
$results = array();
if ( is_array( $new_metadescs ) && $new_metadescs !== array() ) {
foreach ( $new_metadescs as $id => $new_metadesc ) {
$original_metadesc = $original_metadescs[ $id ];
$results[] = wpseo_upsert_new_description( $id, $new_metadesc, $original_metadesc );
}
}
echo json_encode( $results );
die();
wpseo_save_all( 'metadesc' );
}
add_action( 'wp_ajax_wpseo_save_all_descriptions', 'wpseo_save_all_descriptions' );
/**
* Utility function to save values
*
* @param string $what
*/
function wpseo_save_all( $what ) {
check_ajax_referer( 'wpseo-bulk-editor' );
// @todo the WPSEO Utils class can't filter arrays in POST yet.
$new_values = $_POST['items'];
$original_values = $_POST['existing_items'];
$results = array();
if ( is_array( $new_values ) && $new_values !== array() ) {
foreach ( $new_values as $post_id => $new_value ) {
$original_value = $original_values[ $post_id ];
$results[] = wpseo_upsert_new( $what, $post_id, $new_value, $original_value );
}
}
wpseo_ajax_json_echo_die( $results );
}
/**
* Insert a new value
*
* @param string $what
* @param int $post_id
* @param string $new
* @param string $original
*
* @return string
*/
function wpseo_upsert_new( $what, $post_id, $new, $original ) {
$meta_key = WPSEO_Meta::$meta_prefix . $what;
return wpseo_upsert_meta( $post_id, $new, $original, $meta_key, $what );
}
/**
* Create an export and return the URL
*/
function wpseo_get_export() {
check_ajax_referer( 'wpseo-export' );
$include_taxonomy = ( WPSEO_Utils::filter_input( INPUT_POST, 'include_taxonomy' ) === 'true' ) ? true : false;
$export = new WPSEO_Export( $include_taxonomy );
wpseo_ajax_json_echo_die( $export->get_results() );
}
add_action( 'wp_ajax_wpseo_export', 'wpseo_get_export' );
@@ -0,0 +1,194 @@
<?php
/**
* @package WPSEO\Admin
*/
/**
* Performs the load on admin side.
*/
class WPSEO_Admin_Init {
/**
* Holds the WP SEO Options
*
* @var array
*/
private $options;
/**
* Holds the global `$pagenow` variable's value.
*
* @var string
*/
private $pagenow;
/**
* Class constructor
*/
public function __construct() {
$this->options = WPSEO_Options::get_all();
$GLOBALS['wpseo_admin'] = new WPSEO_Admin;
$this->pagenow = $GLOBALS['pagenow'];
add_action( 'admin_init', array( $this, 'redirect_to_about_page' ), 15 );
$this->load_meta_boxes();
$this->load_taxonomy_class();
$this->load_admin_page_class();
$this->load_admin_user_class();
$this->load_yoast_tracking();
$this->load_tour();
$this->load_xml_sitemaps_admin();
}
/**
* Redirect first time or just upgraded users to the about screen.
*/
public function redirect_to_about_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( $this->options['seen_about'] ) {
return;
}
if ( in_array( $this->pagenow, array(
'update.php',
'update-core.php',
'plugins.php',
'plugin-install.php',
) ) ) {
return;
}
// We're redirecting the user to the about screen, let's make sure we don't do it again until he/she upgrades again
$wpseo_option = get_option( 'wpseo' );
$wpseo_option['seen_about'] = true;
update_option( 'wpseo', $wpseo_option );
wp_safe_redirect( admin_url( 'admin.php?page=wpseo_dashboard&intro=1' ) );
}
/**
* Determine whether we should load the meta box class and if so, load it.
*/
private function load_meta_boxes() {
/**
* Filter: 'wpseo_always_register_metaboxes_on_admin' - Allow developers to change whether
* the WPSEO metaboxes are only registered on the typical pages (lean loading) or always
* registered when in admin.
*
* @api bool Whether to always register the metaboxes or not. Defaults to false.
*/
if ( in_array( $this->pagenow, array(
'edit.php',
'post.php',
'post-new.php',
) ) || apply_filters( 'wpseo_always_register_metaboxes_on_admin', false )
) {
$GLOBALS['wpseo_metabox'] = new WPSEO_Metabox;
if ( $this->options['opengraph'] === true || $this->options['twitter'] === true || $this->options['googleplus'] === true ) {
new WPSEO_Social_Admin;
}
}
}
/**
* Determine if we should load our taxonomy edit class and if so, load it.
*/
private function load_taxonomy_class() {
if ( 'edit-tags.php' === $this->pagenow ) {
new WPSEO_Taxonomy;
}
}
/**
* Determine if we should load our admin pages class and if so, load it.
*
* Loads admin page class for all admin pages starting with `wpseo_`.
*/
private function load_admin_user_class() {
if ( in_array( $this->pagenow, array( 'user-edit.php', 'profile.php' ) ) ) {
new WPSEO_Admin_User_Profile;
}
}
/**
* Determine if we should load our admin pages class and if so, load it.
*
* Loads admin page class for all admin pages starting with `wpseo_`.
*/
private function load_admin_page_class() {
$page = filter_input( INPUT_GET, 'page' );
if ( 'admin.php' === $this->pagenow && strpos( $page, 'wpseo' ) === 0 ) {
// For backwards compatabilty, this still needs a global, for now...
$GLOBALS['wpseo_admin_pages'] = new WPSEO_Admin_Pages;
$this->register_i18n_promo_class();
}
}
/**
* Register the promotion class for our GlotPress instance
*
* @link https://github.com/Yoast/i18n-module
*/
function register_i18n_promo_class() {
new yoast_i18n(
array(
'textdomain' => 'wordpress-seo',
'project_slug' => 'wordpress-seo',
'plugin_name' => 'WordPress SEO by Yoast',
'hook' => 'wpseo_admin_footer',
'glotpress_url' => 'http://translate.yoast.com/',
'glotpress_name' => 'Yoast Translate',
'glotpress_logo' => 'https://cdn.yoast.com/wp-content/uploads/i18n-images/Yoast_Translate.svg',
'register_url' => 'http://translate.yoast.com/projects#utm_source=plugin&utm_medium=promo-box&utm_campaign=wpseo-i18n-promo',
)
);
}
/**
* Determine if we're allowed to load our tracking class and if so, load it.
*/
private function load_yoast_tracking() {
if ( $this->options['yoast_tracking'] === true ) {
/**
* @internal this is not a proper lean loading implementation (method_exist will autoload the class),
* but it can't be helped as there are other plugins out there which also use versions
* of the Yoast Tracking class and we need to take that into account unfortunately
*/
if ( method_exists( 'Yoast_Tracking', 'get_instance' ) ) {
add_action( 'yoast_tracking', array( 'Yoast_Tracking', 'get_instance' ) );
}
else {
$GLOBALS['yoast_tracking'] = new Yoast_Tracking;
}
}
}
/**
* See if we should start our tour.
*/
private function load_tour() {
$restart_tour = filter_input( INPUT_GET, 'wpseo_restart_tour' );
if ( $restart_tour ) {
$this->options['ignore_tour'] = false;
update_option( 'wpseo', $this->options );
}
if ( $this->options['tracking_popup_done'] === false || $this->options['ignore_tour'] === false ) {
add_action( 'admin_enqueue_scripts', array( 'WPSEO_Pointers', 'get_instance' ) );
}
}
/**
* See if we should start our XML Sitemaps Admin class
*/
private function load_xml_sitemaps_admin() {
if ( $this->options['enablexmlsitemap'] === true ) {
new WPSEO_Sitemaps_Admin;
}
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @package WPSEO\Admin
* @since 1.8.0
*/
/**
* Customizes user profile.
*/
class WPSEO_Admin_User_Profile {
/**
* Class constructor
*/
public function __construct() {
add_action( 'show_user_profile', array( $this, 'user_profile' ) );
add_action( 'edit_user_profile', array( $this, 'user_profile' ) );
add_action( 'personal_options_update', array( $this, 'process_user_option_update' ) );
add_action( 'edit_user_profile_update', array( $this, 'process_user_option_update' ) );
}
/**
* Filter POST variables.
*
* @param string $var_name
*
* @return mixed
*/
private function filter_input_post( $var_name ) {
$val = filter_input( INPUT_POST, $var_name );
if ( $val ) {
return WPSEO_Option::sanitize_text_field( $val );
}
return '';
}
/**
* Updates the user metas that (might) have been set on the user profile page.
*
* @param int $user_id of the updated user
*/
public function process_user_option_update( $user_id ) {
if ( current_user_can( 'edit_user', $user_id ) ) {
update_user_meta( $user_id, '_yoast_wpseo_profile_updated', time() );
}
if ( $this->filter_input_post( 'wpseo_author_title' ) ) {
check_admin_referer( 'wpseo_user_profile_update', 'wpseo_nonce' );
update_user_meta( $user_id, 'wpseo_title', $this->filter_input_post( 'wpseo_author_title' ) );
update_user_meta( $user_id, 'wpseo_metadesc', $this->filter_input_post( 'wpseo_author_metadesc' ) );
update_user_meta( $user_id, 'wpseo_metakey', $this->filter_input_post( 'wpseo_author_metakey' ) );
update_user_meta( $user_id, 'wpseo_excludeauthorsitemap', $this->filter_input_post( 'wpseo_author_exclude' ) );
}
}
/**
* Add the inputs needed for SEO values to the User Profile page
*
* @param object $user
*/
public function user_profile( $user ) {
if ( ! current_user_can( 'edit_users' ) ) {
return;
}
$options = WPSEO_Options::get_all();
wp_nonce_field( 'wpseo_user_profile_update', 'wpseo_nonce' );
require_once( 'views/user-profile.php' );
}
}
File diff suppressed because it is too large. Load diff
@@ -1,81 +1,76 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin\Bulk Editor
* @since 1.5.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Implements table for bulk description editing.
*/
class WPSEO_Bulk_Description_List_Table extends WPSEO_Bulk_List_Table {
if ( ! class_exists( 'WPSEO_Bulk_Description_List_Table' ) ) {
/**
* Current type for this class will be (meta) description.
*
* @var string
*/
class WPSEO_Bulk_Description_List_Table extends WPSEO_Bulk_List_Table {
protected $page_type = 'description';
/**
* Settings with are used in __construct
*
* @var array
*/
protected $settings = array(
'singular' => 'wpseo_bulk_description',
'plural' => 'wpseo_bulk_descriptions',
'ajax' => true,
);
/**
* Current type for this class will be (meta) description.
*
* @var string
*/
protected $page_type = 'description';
/**
* The field in the database where meta field is saved.
* @var string
*/
protected $target_db_field = 'metadesc';
/**
* Settings with are used in __construct
*
* @var array
*/
protected $settings = array(
'singular' => 'wpseo_bulk_description',
'plural' => 'wpseo_bulk_descriptions',
'ajax' => true,
/**
* The columns shown on the table
*
* @return array
*/
public function get_columns() {
$columns = array(
'col_existing_yoast_seo_metadesc' => __( 'Existing Yoast Meta Description', 'wordpress-seo' ),
'col_new_yoast_seo_metadesc' => __( 'New Yoast Meta Description', 'wordpress-seo' ),
);
/**
* The field in the database where meta field is saved.
* @var string
*/
protected $target_db_field = 'metadesc';
return $this->merge_columns( $columns );
}
/**
* The columns shown on the table
*
* @return array
*/
public function get_columns() {
$columns = array(
'col_existing_yoast_seo_metadesc' => __( 'Existing Yoast Meta Description', 'wordpress-seo' ),
'col_new_yoast_seo_metadesc' => __( 'New Yoast Meta Description', 'wordpress-seo' ),
);
/**
* Parse the metadescription
*
* @param string $column_name
* @param object $record
* @param string $attributes
*
* @return string
*/
protected function parse_page_specific_column( $column_name, $record, $attributes ) {
switch ( $column_name ) {
case 'col_new_yoast_seo_metadesc':
return sprintf(
'<textarea id="%1$s" name="%1$s" class="wpseo-new-metadesc" data-id="%2$s"></textarea>',
'wpseo-new-metadesc-' . $record->ID,
$record->ID
);
break;
return $this->merge_columns( $columns );
case 'col_existing_yoast_seo_metadesc':
// TODO inconsistent return/echo behavior R.
echo $this->parse_meta_data_field( $record->ID, $attributes );
break;
}
}
/**
* Parse the metadescription
*
* @param string $column_name
* @param object $record
* @param string $attributes
*
* @return string
*/
protected function parse_page_specific_column( $column_name, $record, $attributes ) {
switch ( $column_name ) {
case 'col_new_yoast_seo_metadesc' :
return sprintf( '<textarea id="%1$s" name="%1$s" class="wpseo-new-metadesc" data-id="%2$s"></textarea>', 'wpseo-new-metadesc-' . $record->ID, $record->ID );
break;
case 'col_existing_yoast_seo_metadesc':
echo $this->parse_meta_data_field( $record->ID, $attributes );
break;
}
}
} /* End of class */
} /* End of class-exists wrapper */
} /* End of class */
File diff suppressed because it is too large. Load diff
@@ -1,88 +1,85 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin\Bulk Editor
* @since 1.5.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Implements table for bulk title editing.
*/
class WPSEO_Bulk_Title_Editor_List_Table extends WPSEO_Bulk_List_Table {
if ( ! class_exists( 'WPSEO_Bulk_Title_Editor_List_Table' ) ) {
/**
* Current type for this class will be title
*
* @var string
*/
class WPSEO_Bulk_Title_Editor_List_Table extends WPSEO_Bulk_List_Table {
/**
* Current type for this class will be title
*
* @var string
*/
protected $page_type = 'title';
protected $page_type = 'title';
/**
* Settings with are used in __construct
*
* @var array
*/
protected $settings = array(
'singular' => 'wpseo_bulk_title',
'plural' => 'wpseo_bulk_titles',
'ajax' => true,
/**
* Settings with are used in __construct
*
* @var array
*/
protected $settings = array(
'singular' => 'wpseo_bulk_title',
'plural' => 'wpseo_bulk_titles',
'ajax' => true,
);
/**
* The field in the database where meta field is saved.
* @var string
*/
protected $target_db_field = 'title';
/**
* The columns shown on the table
*
* @return array
*/
public function get_columns() {
$columns = array(
'col_existing_yoast_seo_title' => __( 'Existing Yoast SEO Title', 'wordpress-seo' ),
'col_new_yoast_seo_title' => __( 'New Yoast SEO Title', 'wordpress-seo' ),
);
/**
* The field in the database where meta field is saved.
* @var string
*/
protected $target_db_field = 'title';
return $this->merge_columns( $columns );
}
/**
* The columns shown on the table
*
* @return array
*/
public function get_columns() {
/**
* Parse the title columns
*
* @param string $column_name
* @param object $record
* @param string $attributes
*
* @return string
*/
protected function parse_page_specific_column( $column_name, $record, $attributes ) {
$columns = array(
'col_existing_yoast_seo_title' => __( 'Existing Yoast SEO Title', 'wordpress-seo' ),
'col_new_yoast_seo_title' => __( 'New Yoast SEO Title', 'wordpress-seo' ),
);
// Fill meta data if exists in $this->meta_data
$meta_data = ( ! empty( $this->meta_data[ $record->ID ] ) ) ? $this->meta_data[ $record->ID ] : array();
return $this->merge_columns($columns);
switch ( $column_name ) {
case 'col_existing_yoast_seo_title':
// TODO inconsistent echo/return behavior R.
echo $this->parse_meta_data_field( $record->ID, $attributes );
break;
case 'col_new_yoast_seo_title':
return sprintf(
'<input type="text" id="%1$s" name="%1$s" class="wpseo-new-title" data-id="%2$s" />',
'wpseo-new-title-' . $record->ID,
$record->ID
);
break;
}
/**
* Parse the title columns
*
* @param string $column_name
* @param object $record
* @param string $attributes
*
* @return string
*/
protected function parse_page_specific_column( $column_name, $record, $attributes ) {
// Fill meta data if exists in $this->meta_data
$meta_data = ( ! empty( $this->meta_data[$record->ID] ) ) ? $this->meta_data[$record->ID] : array();
switch ( $column_name ) {
case 'col_existing_yoast_seo_title':
echo $this->parse_meta_data_field( $record->ID, $attributes );
break;
case 'col_new_yoast_seo_title':
return sprintf( '<input type="text" id="%1$s" name="%1$s" class="wpseo-new-title" data-id="%2$s" />', 'wpseo-new-title-' . $record->ID, $record->ID );
break;
}
unset( $meta_data );
}
unset( $meta_data );
}
} /* End of class */
} /* End of class-exists wrapper */
} /* End of class */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,222 @@
<?php
/**
* @package WPSEO\Admin\Export
*/
/**
* class WPSEO_Export
*
* Class with functionality to export the WP SEO settings
*/
class WPSEO_Export {
/**
* @var string
*/
private $export = '';
/**
* @var string
*/
private $error = '';
/**
* @var string
*/
public $export_zip_url = '';
/**
* @var boolean
*/
public $success;
/**
* Whether or not the export will include taxonomy metadata
*
* @var boolean
*/
private $include_taxonomy;
/**
* @var array
*/
private $dir = array();
/**
* Class constructor
*
* @param boolean $include_taxonomy Whether to include the taxonomy metadata the plugin creates.
*/
public function __construct( $include_taxonomy = false ) {
$this->include_taxonomy = $include_taxonomy;
$this->dir = wp_upload_dir();
$this->success = $this->export_settings();
}
/**
* Returns an array with status and output message.
*
* @return array $results
*/
public function get_results() {
$results = array();
if ( $this->success ) {
$results['status'] = 'success';
$results['msg'] = sprintf( __( 'Export created: %1$sdownload your export file here%2$s.', 'wordpress-seo' ), '<a href="' . $this->export_zip_url . '">', '</a>' );
}
else {
$results['status'] = 'failure';
$results['msg'] = __( 'Error creating WordPress SEO export: ', 'wordpress-seo' ) . $this->error;
}
return $results;
}
/**
* Exports the current site's WP SEO settings.
*
* @return boolean|string $return true when success, error when failed.
*/
private function export_settings() {
$this->export_header();
foreach ( WPSEO_Options::get_option_names() as $opt_group ) {
$this->write_opt_group( $opt_group, $this->export );
}
$this->taxonomy_metadata();
if ( $this->write_file() ) {
if ( $this->zip_file() ) {
return true;
}
else {
$this->error = __( 'Could not zip settings-file.', 'wordpress-seo' );
return false;
}
}
$this->error = __( 'Could not write settings to file.', 'wordpress-seo' );
return false;
}
/**
* Writes the header of the export file.
*/
private function export_header() {
$this->write_line( '; ' . __( 'This is a settings export file for the WordPress SEO plugin by Yoast.com', 'wordpress-seo' ) . ' - https://yoast.com/wordpress/plugins/seo/' );
if ( $this->include_taxonomy ) {
$this->write_line( '; ' . __( 'This export includes taxonomy metadata', 'wordpress-seo' ) );
}
}
/**
* Writes a line to the export
*
* @param string $line
* @param boolean $newline_first
*/
private function write_line( $line, $newline_first = false ) {
if ( $newline_first ) {
$this->export .= PHP_EOL;
}
$this->export .= $line . PHP_EOL;
}
/**
* Writes an entire option group to the export
*
* @param string $opt_group
*/
private function write_opt_group( $opt_group ) {
$this->write_line( '[' . $opt_group . ']', true );
$options = get_option( $opt_group );
if ( ! is_array( $options ) ) {
return;
}
foreach ( $options as $key => $elem ) {
if ( is_array( $elem ) ) {
for ( $i = 0; $i < count( $elem ); $i ++ ) {
$this->write_setting( $key . '[]', $elem[ $i ] );
}
}
else {
$this->write_setting( $key, $elem );
}
}
}
/**
* Writes a settings line to the export
*
* @param string $key
* @param string $val
*/
private function write_setting( $key, $val ) {
if ( is_string( $val ) ) {
$val = '"' . $val . '"';
}
$this->write_line( $key . ' = ' . $val );
}
/**
* Adds the taxonomy meta data if there is any
*/
private function taxonomy_metadata() {
if ( $this->include_taxonomy ) {
$taxonomy_meta = get_option( 'wpseo_taxonomy_meta' );
if ( is_array( $taxonomy_meta ) ) {
$this->write_line( '[wpseo_taxonomy_meta]', true );
$this->write_setting( 'wpseo_taxonomy_meta', urlencode( json_encode( $taxonomy_meta ) ) );
}
else {
$this->write_line( '; ' . __( 'No taxonomy metadata found', 'wordpress-seo' ), true );
}
}
}
/**
* Writes the settings to our temporary settings.ini file
*
* @return boolean unsigned
*/
private function write_file() {
$handle = fopen( $this->dir['path'] . '/settings.ini', 'w' );
if ( ! $handle ) {
return false;
}
$res = fwrite( $handle, $this->export );
if ( ! $res ) {
return false;
}
fclose( $handle );
return true;
}
/**
* Zips the settings ini file
*
* @return boolean unsigned
*/
private function zip_file() {
chdir( $this->dir['path'] );
$zip = new PclZip( './settings.zip' );
if ( 0 === $zip->create( './settings.ini' ) ) {
return false;
}
$this->export_zip_url = $this->dir['url'] . '/settings.zip';
return true;
}
}
@@ -0,0 +1,98 @@
<?php
/**
* @package WPSEO\Admin\Import\External
*/
/**
* class WPSEO_Import_WooThemes_SEO
*
* Class with functionality to import WP SEO settings from WooThemes SEO
*/
class WPSEO_Import_AIOSEO extends WPSEO_Import_External {
/**
* Holds the AOIOSEO options
*
* @var array
*/
private $aioseo_options;
/**
* Import All In One SEO settings
*/
public function __construct() {
parent::__construct();
$this->aioseo_options = get_option( 'aioseop_options' );
$this->import_metas();
$this->import_ga();
}
/**
* Import All In One SEO meta values
*/
private function import_metas() {
WPSEO_Meta::replace_meta( '_aioseop_description', WPSEO_Meta::$meta_prefix . 'metadesc', $this->replace );
WPSEO_Meta::replace_meta( '_aioseop_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $this->replace );
WPSEO_Meta::replace_meta( '_aioseop_title', WPSEO_Meta::$meta_prefix . 'title', $this->replace );
}
/**
* Import the Google Analytics settings
*/
private function import_ga() {
if ( isset( $this->aioseo_options['aiosp_google_analytics_id'] ) ) {
if ( get_option( 'yst_ga' ) === false ) {
update_option( 'yst_ga', $this->determine_ga_settings() );
}
$plugin_install_nonce = wp_create_nonce( 'install-plugin_google-analytics-for-wordpress' ); // Use the old name because that's the WordPress.org repo
$this->set_msg( __( sprintf(
'All in One SEO data successfully imported. Would you like to %sdisable the All in One SEO plugin%s. You\'ve had Google Analytics enabled in All in One SEO, would you like to install our %sGoogle Analytics plugin%s?',
'<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_tools&tool=import-export&deactivate_aioseo=1#top#import-seo' ) ) . '">',
'</a>',
'<a href="' . esc_url( admin_url( 'update.php?action=install-plugin&plugin=google-analytics-for-wordpress&_wpnonce=' . $plugin_install_nonce ) ) . '">',
'</a>'
), 'wordpress-seo' ) );
}
else {
$this->set_msg( __( sprintf( 'All in One SEO data successfully imported. Would you like to %sdisable the All in One SEO plugin%s.', '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_tools&tool=import-export&deactivate_aioseo=1#top#import-seo' ) ) . '">', '</a>' ), 'wordpress-seo' ) );
}
}
/**
* Determine the appropriate GA settings for this site
*
* @return array $ga_settings
*/
private function determine_ga_settings() {
$ga_universal = 0;
if ( $this->aioseo_options['aiosp_ga_use_universal_analytics'] == 'on' ) {
$ga_universal = 1;
}
$ga_track_outbound = 0;
if ( $this->aioseo_options['aiosp_ga_track_outbound_links'] == 'on' ) {
$ga_track_outbound = 1;
}
$ga_anonymize_ip = 0;
if ( $this->aioseo_options['aiosp_ga_anonymize_ip'] == 'on' ) {
$ga_anonymize_ip = 1;
}
return array(
'ga_general' => array(
'manual_ua_code' => (int) 1,
'manual_ua_code_field' => $this->aioseo_options['aiosp_google_analytics_id'],
'enable_universal' => $ga_universal,
'track_outbound' => $ga_track_outbound,
'ignore_users' => (array) $this->aioseo_options['aiosp_ga_exclude_users'],
'anonymize_ips' => (int) $ga_anonymize_ip,
),
);
}
}
@@ -0,0 +1,191 @@
<?php
/**
* @package WPSEO\Admin\Import\External
*/
/**
* class WPSEO_Import_External
*
* Class with functionality to import WP SEO settings from other plugins
*/
class WPSEO_Import_External {
/**
* Whether or not to delete old data
*
* @var boolean
*/
protected $replace;
/**
* Message about the import
*
* @var string
*/
public $msg = '';
/**
* Class constructor
*
* @param boolean $replace
*/
public function __construct( $replace = false ) {
$this->replace = $replace;
WPSEO_Options::initialize();
}
/**
* Convenience function to set import message
*
* @param string $msg
*/
protected function set_msg( $msg ) {
if ( ! empty( $this->msg ) ) {
$this->msg .= PHP_EOL;
}
$this->msg .= $msg;
}
/**
* Deletes an option depending on the class replace state
*
* @param string $option
*/
protected function perhaps_delete( $option ) {
if ( $this->replace ) {
delete_option( $option );
}
}
/**
* Import HeadSpace SEO settings
*/
public function import_headspace() {
global $wpdb;
WPSEO_Meta::replace_meta( '_headspace_description', WPSEO_Meta::$meta_prefix . 'metadesc', $this->replace );
WPSEO_Meta::replace_meta( '_headspace_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $this->replace );
WPSEO_Meta::replace_meta( '_headspace_page_title', WPSEO_Meta::$meta_prefix . 'title', $this->replace );
/* @todo [JRF => whomever] verify how headspace sets these metas ( 'noindex', 'nofollow', 'noarchive', 'noodp', 'noydir' )
* and if the values saved are concurrent with the ones we use (i.e. 0/1/2) */
WPSEO_Meta::replace_meta( '_headspace_noindex', WPSEO_Meta::$meta_prefix . 'meta-robots-noindex', $this->replace );
WPSEO_Meta::replace_meta( '_headspace_nofollow', WPSEO_Meta::$meta_prefix . 'meta-robots-nofollow', $this->replace );
/* @todo - [JRF => whomever] check if this can be done more efficiently by querying only the meta table
* possibly directly changing it using concat on the existing values
*/
$posts = $wpdb->get_results( "SELECT ID FROM $wpdb->posts" );
if ( is_array( $posts ) && $posts !== array() ) {
foreach ( $posts as $post ) {
$custom = get_post_custom( $post->ID );
$robotsmeta_adv = '';
if ( isset( $custom['_headspace_noarchive'] ) ) {
$robotsmeta_adv .= 'noarchive,';
}
if ( isset( $custom['_headspace_noodp'] ) ) {
$robotsmeta_adv .= 'noodp,';
}
if ( isset( $custom['_headspace_noydir'] ) ) {
$robotsmeta_adv .= 'noydir';
}
$robotsmeta_adv = preg_replace( '`,$`', '', $robotsmeta_adv );
WPSEO_Meta::set_value( 'meta-robots-adv', $robotsmeta_adv, $post->ID );
}
}
if ( $this->replace ) {
$hs_meta = array( 'noarchive', 'noodp', 'noydir' );
foreach ( $hs_meta as $meta ) {
delete_post_meta_by_key( '_headspace_' . $meta );
}
unset( $hs_meta, $meta );
}
$this->set_msg( __( 'HeadSpace2 data successfully imported', 'wordpress-seo' ) );
}
/**
* Import from Joost's old robots meta plugin
*/
public function import_robots_meta() {
global $wpdb;
$posts = $wpdb->get_results( "SELECT ID, robotsmeta FROM $wpdb->posts" );
if ( ! $posts ) {
$this->set_msg( __( 'Error: no Robots Meta data found to import.', 'wordpress-seo' ) );
return;
}
if ( is_array( $posts ) && $posts !== array() ) {
foreach ( $posts as $post ) {
// sync all possible settings
if ( $post->robotsmeta ) {
$pieces = explode( ',', $post->robotsmeta );
foreach ( $pieces as $meta ) {
switch ( $meta ) {
case 'noindex':
WPSEO_Meta::set_value( 'meta-robots-noindex', '1', $post->ID );
break;
case 'index':
WPSEO_Meta::set_value( 'meta-robots-noindex', '2', $post->ID );
break;
case 'nofollow':
WPSEO_Meta::set_value( 'meta-robots-nofollow', '1', $post->ID );
break;
}
}
}
}
}
$this->set_msg( __( sprintf( 'Robots Meta values imported. We recommend %sdisabling the Robots-Meta plugin%s to avoid any conflicts.', '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_tools&tool=import-export&deactivate_robots_meta=1#top#import-other' ) ) . '">', '</a>' ), 'wordpress-seo' ) );
}
/**
* Import from old Yoast RSS Footer plugin
*/
public function import_rss_footer() {
$optold = get_option( 'RSSFooterOptions' );
$optnew = get_option( 'wpseo_rss' );
if ( $optold['position'] == 'after' ) {
if ( $optnew['rssafter'] === '' || $optnew['rssafter'] === WPSEO_Options::get_default( 'wpseo_rss', 'rssafter' ) ) {
$optnew['rssafter'] = $optold['footerstring'];
}
}
else {
/* @internal Uncomment the second part if a default would be given to the rssbefore value */
if ( $optnew['rssbefore'] === '' /*|| $optnew['rssbefore'] === WPSEO_Options::get_default( 'wpseo_rss', 'rssbefore' )*/ ) {
$optnew['rssbefore'] = $optold['footerstring'];
}
}
update_option( 'wpseo_rss', $optnew );
$this->set_msg( __( 'RSS Footer options imported successfully.', 'wordpress-seo' ) );
}
/**
* Import from Yoast Breadcrumbs plugin
*/
public function import_yoast_breadcrumbs() {
$optold = get_option( 'yoast_breadcrumbs' );
$optnew = get_option( 'wpseo_internallinks' );
if ( is_array( $optold ) && $optold !== array() ) {
foreach ( $optold as $opt => $val ) {
if ( is_bool( $val ) && $val === true ) {
$optnew[ 'breadcrumbs-' . $opt ] = true;
}
else {
$optnew[ 'breadcrumbs-' . $opt ] = $val;
}
}
unset( $opt, $val );
update_option( 'wpseo_internallinks', $optnew );
$this->set_msg( __( 'Yoast Breadcrumbs options imported successfully.', 'wordpress-seo' ) );
}
else {
$this->set_msg( __( 'Yoast Breadcrumbs options could not be found', 'wordpress-seo' ) );
}
}
}
@@ -0,0 +1,146 @@
<?php
/**
* @package WPSEO\Admin\Import\External
*/
/**
* class WPSEO_Import_WooThemes_SEO
*
* Class with functionality to import WP SEO settings from WooThemes SEO
*/
class WPSEO_Import_WooThemes_SEO extends WPSEO_Import_External {
/**
* Class constructor
*/
public function __construct() {
parent::__construct();
$this->import_home();
$this->import_option( 'seo_woo_single_layout', 'post' );
$this->import_option( 'seo_woo_page_layout', 'page' );
$this->import_archive_option();
$this->import_custom_values( 'seo_woo_meta_home_desc', 'metadesc-home-wpseo' );
$this->import_custom_values( 'seo_woo_meta_home_key', 'metakey-home-wpseo' );
$this->import_metas();
update_option( 'wpseo_titles', $this->options );
$this->set_msg( __( 'WooThemes SEO framework settings &amp; data successfully imported.', 'wordpress-seo' ) );
}
/**
* Holds the WPSEO Title Options
*
* @var array
*/
private $options;
/**
* Import options.
*
* @param string $option
* @param string $post_type
*/
private function import_option( $option, $post_type ) {
switch ( get_option( $option ) ) {
case 'a':
$this->options[ 'title-' . $post_type ] = '%%title%% %%sep%% %%sitename%%';
break;
case 'b':
$this->options[ 'title-' . $post_type ] = '%%title%%';
break;
case 'c':
$this->options[ 'title-' . $post_type ] = '%%sitename%% %%sep%% %%title%%';
break;
case 'd':
$this->options[ 'title-' . $post_type ] = '%%title%% %%sep%% %%sitedesc%%';
break;
case 'e':
$this->options[ 'title-' . $post_type ] = '%%sitename%% %%sep%% %%title%% %%sep%% %%sitedesc%%';
break;
}
$this->perhaps_delete( $option );
}
/**
* Import the archive layout for all taxonomies
*/
private function import_archive_option() {
$reinstate_replace = false;
if ( $this->replace ) {
$this->replace = false;
$reinstate_replace = true;
}
$taxonomies = get_taxonomies( array( 'public' => true ), 'names' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
foreach ( $taxonomies as $tax ) {
$this->import_option( 'seo_woo_archive_layout', 'tax-' . $tax );
}
}
if ( $reinstate_replace ) {
$this->replace = true;
$this->perhaps_delete( 'seo_woo_archive_layout' );
}
}
/**
* Import custom descriptions and meta keys
*
* @param string $option
* @param string $key
*/
private function import_custom_values( $option, $key ) {
// Import the custom homepage description
if ( 'c' == get_option( $option ) ) {
$this->options[ $key ] = get_option( $option . '_custom' );
}
$this->perhaps_delete( $option );
$this->perhaps_delete( $option . '_custom' );
}
/**
* Imports the WooThemes SEO homepage settings
*/
private function import_home() {
switch ( get_option( 'seo_woo_home_layout' ) ) {
case 'a':
$this->options['title-home-wpseo'] = '%%sitename%% %%sep%% %%sitedesc%%';
break;
case 'b':
$this->options['title-home-wpseo'] = '%%sitename%% ' . get_option( 'seo_woo_paged_var' ) . ' %%pagenum%%';
break;
case 'c':
$this->options['title-home-wpseo'] = '%%sitedesc%%';
break;
}
$this->perhaps_delete( 'seo_woo_home_layout' );
}
/**
* Import meta values if they're applicable
*/
private function import_metas() {
WPSEO_Meta::replace_meta( 'seo_follow', WPSEO_Meta::$meta_prefix . 'meta-robots-nofollow', $this->replace );
WPSEO_Meta::replace_meta( 'seo_noindex', WPSEO_Meta::$meta_prefix . 'meta-robots-noindex', $this->replace );
// If WooSEO is set to use the Woo titles, import those
if ( 'true' == get_option( 'seo_woo_wp_title' ) ) {
WPSEO_Meta::replace_meta( 'seo_title', WPSEO_Meta::$meta_prefix . 'title', $this->replace );
}
// If WooSEO is set to use the Woo meta descriptions, import those
if ( 'b' == get_option( 'seo_woo_meta_single_desc' ) ) {
WPSEO_Meta::replace_meta( 'seo_description', WPSEO_Meta::$meta_prefix . 'metadesc', $this->replace );
}
// If WooSEO is set to use the Woo meta keywords, import those
if ( 'b' == get_option( 'seo_woo_meta_single_key' ) ) {
WPSEO_Meta::replace_meta( 'seo_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $this->replace );
}
foreach ( array( 'seo_woo_wp_title', 'seo_woo_meta_single_desc', 'seo_woo_meta_single_key' ) as $option ) {
$this->perhaps_delete( $option );
}
}
}
@@ -0,0 +1,183 @@
<?php
/**
* @package WPSEO\Admin\Import
*/
/**
* class WPSEO_Import
*
* Class with functionality to import the WP SEO settings
*/
class WPSEO_Import {
/**
* Message about the import
*
* @var string
*/
public $msg = '';
/**
* @var array
*/
private $file;
/**
* @var string
*/
private $filename;
/**
* @var string
*/
private $old_wpseo_version = null;
/**
* @var string
*/
private $path;
/**
* @var array
*/
private $upload_dir;
/**
* Class constructor
*/
public function __construct() {
if ( ! $this->handle_upload() ) {
return;
}
$this->determine_path();
if ( ! $this->unzip_file() ) {
$this->clean_up();
return;
}
$this->parse_options();
$this->clean_up();
}
/**
* Handle the file upload
*
* @return boolean
*/
private function handle_upload() {
$this->file = wp_handle_upload( $_FILES['settings_import_file'] );
if ( is_wp_error( $this->file ) ) {
$this->msg = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . $this->file->get_error_message();
return false;
}
elseif ( ! isset( $this->file['file'] ) ) {
$this->msg = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'Upload failed.', 'wordpress-seo' );
return false;
}
return true;
}
/**
* Determine the path to the import file
*/
private function determine_path() {
$this->upload_dir = wp_upload_dir();
if ( ! defined( 'DIRECTORY_SEPARATOR' ) ) {
define( 'DIRECTORY_SEPARATOR', '/' );
}
$this->path = $this->upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'wpseo-import' . DIRECTORY_SEPARATOR;
if ( ! isset( $GLOBALS['wp_filesystem'] ) || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
WP_Filesystem();
}
}
/**
* Unzip the file
*
* @return boolean
*/
private function unzip_file() {
$unzipped = unzip_file( $this->file['file'], $this->path );
if ( is_wp_error( $unzipped ) ) {
$this->msg = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . sprintf( __( 'Unzipping failed with error "%s".', 'wordpress-seo' ), $unzipped->get_error_message() );
return false;
}
$this->filename = $this->path . 'settings.ini';
if ( ! is_file( $this->filename ) || ! is_readable( $this->filename ) ) {
$this->msg = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'Unzipping failed - file settings.ini not found.', 'wordpress-seo' );
return false;
}
return true;
}
/**
* Parse the option file
*/
private function parse_options() {
$options = parse_ini_file( $this->filename, true );
if ( is_array( $options ) && $options !== array() ) {
if ( isset( $options['wpseo']['version'] ) && $options['wpseo']['version'] !== '' ) {
$this->old_wpseo_version = $options['wpseo']['version'];
}
foreach ( $options as $name => $opt_group ) {
$this->parse_option_group( $name, $opt_group, $options );
}
$this->msg = __( 'Settings successfully imported.', 'wordpress-seo' );
}
else {
$this->msg = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'No settings found in file.', 'wordpress-seo' );
}
}
/**
* Parse the option group and import it
*
* @param string $name
* @param array $opt_group
* @param array $options
*/
private function parse_option_group( $name, $opt_group, $options ) {
if ( $name === 'wpseo_taxonomy_meta' ) {
$opt_group = json_decode( urldecode( $opt_group['wpseo_taxonomy_meta'] ), true );
}
// Make sure that the imported options are cleaned/converted on import
$option_instance = WPSEO_Options::get_option_instance( $name );
if ( is_object( $option_instance ) && method_exists( $option_instance, 'import' ) ) {
$option_instance->import( $opt_group, $this->old_wpseo_version, $options );
}
elseif ( WP_DEBUG === true || ( defined( 'WPSEO_DEBUG' ) && WPSEO_DEBUG === true ) ) {
$this->msg = sprintf( __( 'Setting "%s" is no longer used and has been discarded.', 'wordpress-seo' ), $name );
}
}
/**
* Remove the files
*/
private function clean_up() {
if ( file_exists( $this->filename ) && is_writable( $this->filename ) ) {
unlink( $this->filename );
}
if ( file_exists( $this->file['file'] ) && is_writable( $this->file['file'] ) ) {
unlink( $this->file['file'] );
}
if ( file_exists( $this->path ) && is_writable( $this->path ) ) {
rmdir( $this->path );
}
}
}
File diff suppressed because it is too large. Load diff
@@ -1,157 +1,151 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* This class adds the Social tab to the WP SEO metabox and makes sure the settings are saved.
*/
class WPSEO_Social_Admin extends WPSEO_Metabox {
if ( ! class_exists( 'WPSEO_Social_Admin' ) ) {
/**
* This class adds the Social tab to the WP SEO metabox and makes sure the settings are saved.
* Class constructor
*/
class WPSEO_Social_Admin extends WPSEO_Metabox {
public function __construct() {
add_action( 'wpseo_tab_translate', array( $this, 'translate_meta_boxes' ) );
add_action( 'wpseo_tab_header', array( $this, 'tab_header' ), 60 );
add_action( 'wpseo_tab_content', array( $this, 'tab_content' ) );
add_filter( 'wpseo_save_metaboxes', array( $this, 'save_meta_boxes' ), 10, 1 );
add_action( 'wpseo_save_compare_data', array( $this, 'og_data_compare' ), 10, 1 );
}
/**
* Class constructor
*/
public function __construct() {
add_action( 'wpseo_tab_translate', array( $this, 'translate_meta_boxes' ) );
add_action( 'wpseo_tab_header', array( $this, 'tab_header' ), 60 );
add_action( 'wpseo_tab_content', array( $this, 'tab_content' ) );
add_filter( 'wpseo_save_metaboxes', array( $this, 'save_meta_boxes' ), 10, 1 );
add_action( 'wpseo_save_compare_data', array( $this, 'og_data_compare' ), 10, 1 );
/**
* Translate text strings for use in the meta box
*
* IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to
* the main meta box definition array in the class WPSEO_Meta() as well!!!!
*/
public static function translate_meta_boxes() {
$title_text = __( 'If you don\'t want to use the post title for sharing the post on %s but instead want another title there, write it here.', 'wordpress-seo' );
$description_text = __( 'If you don\'t want to use the meta description for sharing the post on %s but want another description there, write it here.', 'wordpress-seo' );
$image_text = __( 'If you want to override the image used on %s for this post, upload / choose an image or add the URL here.', 'wordpress-seo' );
$options = WPSEO_Options::get_all();
$social_networks = array(
'opengraph' => __( 'Facebook', 'wordpress-seo' ),
'twitter' => __( 'Twitter', 'wordpress-seo' ),
'googleplus' => __( 'Google+', 'wordpress-seo' ),
);
foreach ( $social_networks as $network => $label ) {
if ( true === $options[ $network ] ) {
if ( 'googleplus' == $network ) {
$network = 'google-plus'; // Yuck, I know.
}
self::$meta_fields['social'][ $network . '-title' ]['title'] = sprintf( __( '%s Title', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-title' ]['description'] = sprintf( $title_text, $label );
self::$meta_fields['social'][ $network . '-description' ]['title'] = sprintf( __( '%s Description', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-description' ]['description'] = sprintf( $description_text, $label );
self::$meta_fields['social'][ $network . '-image' ]['title'] = sprintf( __( '%s Image', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-image' ]['description'] = sprintf( $image_text, $label );
}
}
}
/**
* Translate text strings for use in the meta box
*
* IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to
* the main meta box definition array in the class WPSEO_Meta() as well!!!!
*/
public static function translate_meta_boxes() {
$title_text = __( 'If you don\'t want to use the post title for sharing the post on %s but instead want another title there, write it here.', 'wordpress-seo' );
$description_text = __( 'If you don\'t want to use the meta description for sharing the post on %s but want another description there, write it here.', 'wordpress-seo' );
$image_text = __( 'If you want to override the image used on %s for this post, upload / choose an image or add the URL here.', 'wordpress-seo' );
/**
* Output the tab header for the Social tab
*/
public function tab_header() {
echo '<li class="social"><a class="wpseo_tablink" href="#wpseo_social">', __( 'Social', 'wordpress-seo' ), '</a></li>';
}
$options = WPSEO_Options::get_all();
/**
* Output the tab content
*/
public function tab_content() {
$content = '';
foreach ( $this->get_meta_field_defs( 'social' ) as $meta_key => $meta_field ) {
$content .= $this->do_meta_box( $meta_field, $meta_key );
}
$this->do_tab( 'social', __( 'Social', 'wordpress-seo' ), $content );
}
foreach (
array(
'opengraph' => __( 'Facebook', 'wordpress-seo' ),
'twitter' => __( 'Twitter', 'wordpress-seo' ),
'googleplus' => __( 'Google+', 'wordpress-seo' ),
) as $network => $label
) {
if ( true === $options[ $network ] ) {
if ( 'googleplus' == $network ) {
$network = 'google-plus'; // Yuck, I know.
}
self::$meta_fields['social'][ $network . '-title' ]['title'] = sprintf( __( '%s Title', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-title' ]['description'] = sprintf( $title_text, $label );
/**
* Filter over the meta boxes to save, this function adds the Social meta boxes.
*
* @param array $field_defs Array of metaboxes to save.
*
* @return array
*/
public function save_meta_boxes( $field_defs ) {
return array_merge( $field_defs, $this->get_meta_field_defs( 'social' ) );
}
self::$meta_fields['social'][ $network . '-description' ]['title'] = sprintf( __( '%s Description', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-description' ]['description'] = sprintf( $description_text, $label );
/**
* This method will compare opengraph fields with the posted values.
*
* When fields are changed, the facebook cache will be purge.
*
* @param object $post
*/
public function og_data_compare( $post ) {
self::$meta_fields['social'][ $network . '-image' ]['title'] = sprintf( __( '%s Image', 'wordpress-seo' ), $label );
self::$meta_fields['social'][ $network . '-image' ]['description'] = sprintf( $image_text, $label );
// Check if post data is available, if post_id is set and if original post_status is publish
if (
! empty( $_POST ) && ! empty( $post->ID ) && $post->post_status == 'publish' &&
isset ( $_POST['original_post_status'] ) && $_POST['original_post_status'] === 'publish'
) {
$fields_to_compare = array(
'opengraph-title',
'opengraph-description',
'opengraph-image',
);
$reset_facebook_cache = false;
foreach ( $fields_to_compare as $field_to_compare ) {
$old_value = self::get_value( $field_to_compare, $post->ID );
$new_value = self::get_post_value( self::$form_prefix . $field_to_compare );
if ( $old_value !== $new_value ) {
$reset_facebook_cache = true;
break;
}
}
unset( $field_to_compare, $old_value, $new_value );
}
/**
* Output the tab header for the Social tab
*/
public function tab_header() {
echo '<li class="social"><a class="wpseo_tablink" href="#wpseo_social">' . __( 'Social', 'wordpress-seo' ) . '</a></li>';
}
/**
* Output the tab content
*/
public function tab_content() {
$content = '';
foreach ( $this->get_meta_field_defs( 'social' ) as $meta_key => $meta_field ) {
$content .= $this->do_meta_box( $meta_field, $meta_key );
}
$this->do_tab( 'social', __( 'Social', 'wordpress-seo' ), $content );
}
/**
* Filter over the meta boxes to save, this function adds the Social meta boxes.
*
* @param array $field_defs Array of metaboxes to save.
*
* @return array
*/
public function save_meta_boxes( $field_defs ) {
return array_merge( $field_defs, $this->get_meta_field_defs( 'social' ) );
}
/**
* This method will compare opengraph fields with the posted values.
*
* When fields are changed, the facebook cache will be purge.
*
* @param object $post
*/
public function og_data_compare( $post ) {
// Check if post data is available, if post_id is set and if original post_status is publish
if ( ! empty( $_POST ) && ! empty( $post->ID ) && $post->post_status == 'publish' && $_POST['original_post_status'] === 'publish' ) {
$fields_to_compare = array(
'opengraph-title',
'opengraph-description',
'opengraph-image'
if ( $reset_facebook_cache ) {
wp_remote_get(
'https://graph.facebook.com/?id=' . get_permalink( $post->ID ) . '&scrape=true&method=post'
);
$reset_facebook_cache = false;
foreach ( $fields_to_compare AS $field_to_compare ) {
$old_value = self::get_value( $field_to_compare, $post->ID );
$new_value = self::get_post_value( self::$form_prefix . $field_to_compare );
if ( $old_value !== $new_value ) {
$reset_facebook_cache = true;
break;
}
}
if ( $reset_facebook_cache ) {
wp_remote_get(
'https://graph.facebook.com/?id=' . get_permalink( $post->ID ) . '&scrape=true&method=post'
);
}
}
}
}
/********************** DEPRECATED METHODS **********************/
/********************** DEPRECATED METHODS **********************/
/**
* Define the meta boxes for the Social tab
*
* @deprecated 1.5.0
* @deprecated use WPSEO_Meta::get_meta_field_defs()
* @see WPSEO_Meta::get_meta_field_defs()
*
* @param string $post_type
*
* @return array Array containing the meta boxes
*/
public function get_meta_boxes( $post_type = 'post' ) {
_deprecated_function( __METHOD__, 'WPSEO 1.5.0', 'WPSEO_Meta::get_meta_field_defs()' );
/**
* Define the meta boxes for the Social tab
*
* @deprecated 1.5.0
* @deprecated use WPSEO_Meta::get_meta_field_defs()
* @see WPSEO_Meta::get_meta_field_defs()
*
* @param string $post_type
*
* @return array Array containing the meta boxes
*/
public function get_meta_boxes( $post_type = 'post' ) {
_deprecated_function( __METHOD__, 'WPSEO 1.5.0', 'WPSEO_Meta::get_meta_field_defs()' );
return $this->get_meta_field_defs( 'social' );
}
return $this->get_meta_field_defs( 'social' );
}
} /* End of class */
} /* End of class-exists wrapper */
} /* End of class */
@@ -1,129 +1,139 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
* @since 1.7.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Contains list of conflicting plugins.
*/
class WPSEO_Plugin_Conflict extends Yoast_Plugin_Conflict {
if ( ! class_exists( 'WPSEO_Plugin_Conflict' ) ) {
class WPSEO_Plugin_Conflict extends Yoast_Plugin_Conflict {
/**
* The plugins must be grouped per section.
*
* It's possible to check for each section if there are conflicting plugin
*
* @var array
*/
protected $plugins = array(
// The plugin which are writing OG metadata
'open_graph' => array(
'2-click-socialmedia-buttons/2-click-socialmedia-buttons.php',
// 2 Click Social Media Buttons
'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook
'add-meta-tags/add-meta-tags.php', // Add Meta Tags
'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail
'facebook/facebook.php', // Facebook (official plugin)
'facebook-awd/AWD_facebook.php', // Facebook AWD All in one
'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php',
// Facebook Featured Image & OG Meta Tags
'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags
'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
// Facebook Open Graph Meta Tags for WordPress
'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag
'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer
'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php',
// Fedmich's Facebook Open Graph Meta
'header-footer/plugin.php', // Header and Footer
'network-publisher/networkpub.php', // Network Publisher
'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG
'social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.php',
// NextScripts SNAP
'opengraph/opengraph.php', // Open Graph
'open-graph-protocol-framework/open-graph-protocol-framework.php',
// Open Graph Protocol Framework
'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments
'seo-ultimate/seo-ultimate.php', // SEO Ultimate
'sexybookmarks/sexy-bookmarks.php', // Shareaholic
'shareaholic/sexy-bookmarks.php', // Shareaholic
'sharepress/sharepress.php', // SharePress
'simple-facebook-connect/sfc.php', // Simple Facebook Connect
'social-discussions/social-discussions.php', // Social Discussions
'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit
'socialize/socialize.php', // Socialize
'only-tweet-like-share-and-google-1/tweet-like-plusone.php',
// Tweet, Like, Google +1 and Share
'wordbooker/wordbooker.php', // Wordbooker
'wpsso/wpsso.php', // WordPress Social Sharing Optimization
'wp-caregiver/wp-caregiver.php', // WP Caregiver
'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php',
// WP Facebook Like Send & Open Graph Meta
'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol
'wp-ogp/wp-ogp.php', // WP-OGP
'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin
),
'xml_sitemaps' => array(
'google-sitemap-plugin/google-sitemap-plugin.php', // Google Sitemap (BestWebSoft)
'xml-sitemaps/xml-sitemaps.php', // XML Sitemaps (Denis de Bernardy and Mike Koepke)
'bwp-google-xml-sitemaps/bwp-simple-gxs.php', // Better WordPress Google XML Sitemaps (Khang Minh)
'google-sitemap-generator/sitemap.php', // Google XML Sitemaps (Arne Brachhold)
'xml-sitemap-feed/xml-sitemap.php', // XML Sitemap & Google News feeds (RavanH)
'google-monthly-xml-sitemap/monthly-xml-sitemap.php', // Google Monthly XML Sitemap (Andrea Pernici)
'simple-google-sitemap-xml/simple-google-sitemap-xml.php', // Simple Google Sitemap XML (iTx Technologies)
'another-simple-xml-sitemap/another-simple-xml-sitemap.php', // Another Simple XML Sitemap
'xml-maps/google-sitemap.php', // Xml Sitemap (Jason Martens)
'google-xml-sitemap-generator-by-anton-dachauer/adachauer-google-xml-sitemap.php', // Google XML Sitemap Generator by Anton Dachauer (Anton Dachauer)
'wp-xml-sitemap/wp-xml-sitemap.php', // WP XML Sitemap (Team Vivacity)
'sitemap-generator-for-webmasters/sitemap.php', // Sitemap Generator for Webmasters (iwebslogtech)
'xml-sitemap-xml-sitemapcouk/xmls.php', // XML Sitemap - XML-Sitemap.co.uk (Simon Hancox)
'sewn-in-xml-sitemap/sewn-xml-sitemap.php', // Sewn In XML Sitemap (jcow)
'rps-sitemap-generator/rps-sitemap-generator.php', // RPS Sitemap Generator (redpixelstudios)
)
);
/**
* Overrides instance to set with this class as class
*
* @return Yoast_Plugin_Conflict
*/
public static function get_instance( $classname = __CLASS__ ) {
return parent::get_instance( $classname );
}
/**
* After activating any plugin, this method will be executed by a hook.
*
* If the activated plugin is conflicting with ours a notice will be shown.
*
* @param string|bool $plugin
*
*/
public static function hook_check_for_plugin_conflicts( $plugin = false ) {
// The instance of itself
$instance = self::get_instance();
// Only add plugin as active plugin if $plugin isn't false
if ( $plugin ) {
// Because it's just activated
$instance->add_active_plugin( $instance->find_plugin_category( $plugin ), $plugin );
}
$plugin_sections = array(
'open_graph' => 'open graph',
'xml_sitemaps' => 'xml sitemaps'
);
$instance->check_plugin_conflicts( $plugin_sections );
}
/**
* The plugins must be grouped per section.
*
* It's possible to check for each section if there are conflicting plugin
*
* @var array
*/
protected $plugins = array(
// The plugin which are writing OG metadata
'open_graph' => array(
'2-click-socialmedia-buttons/2-click-socialmedia-buttons.php',
// 2 Click Social Media Buttons
'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook
'add-meta-tags/add-meta-tags.php', // Add Meta Tags
'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail
'facebook/facebook.php', // Facebook (official plugin)
'facebook-awd/AWD_facebook.php', // Facebook AWD All in one
'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php',
// Facebook Featured Image & OG Meta Tags
'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags
'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
// Facebook Open Graph Meta Tags for WordPress
'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag
'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer
'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php',
// Fedmich's Facebook Open Graph Meta
'header-footer/plugin.php', // Header and Footer
'network-publisher/networkpub.php', // Network Publisher
'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG
'opengraph/opengraph.php', // Open Graph
'open-graph-protocol-framework/open-graph-protocol-framework.php',
// Open Graph Protocol Framework
'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments
'seo-ultimate/seo-ultimate.php', // SEO Ultimate
'sexybookmarks/sexy-bookmarks.php', // Shareaholic
'shareaholic/sexy-bookmarks.php', // Shareaholic
'sharepress/sharepress.php', // SharePress
'simple-facebook-connect/sfc.php', // Simple Facebook Connect
'social-discussions/social-discussions.php', // Social Discussions
'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit
'socialize/socialize.php', // Socialize
'only-tweet-like-share-and-google-1/tweet-like-plusone.php',
// Tweet, Like, Google +1 and Share
'wordbooker/wordbooker.php', // Wordbooker
'wpsso/wpsso.php', // WordPress Social Sharing Optimization
'wp-caregiver/wp-caregiver.php', // WP Caregiver
'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php',
// WP Facebook Like Send & Open Graph Meta
'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol
'wp-ogp/wp-ogp.php', // WP-OGP
'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin
),
'xml_sitemaps' => array(
'google-sitemap-plugin/google-sitemap-plugin.php',
// Google Sitemap (BestWebSoft)
'xml-sitemaps/xml-sitemaps.php',
// XML Sitemaps (Denis de Bernardy and Mike Koepke)
'bwp-google-xml-sitemaps/bwp-simple-gxs.php',
// Better WordPress Google XML Sitemaps (Khang Minh)
'google-sitemap-generator/sitemap.php',
// Google XML Sitemaps (Arne Brachhold)
'xml-sitemap-feed/xml-sitemap.php',
// XML Sitemap & Google News feeds (RavanH)
'google-monthly-xml-sitemap/monthly-xml-sitemap.php',
// Google Monthly XML Sitemap (Andrea Pernici)
'simple-google-sitemap-xml/simple-google-sitemap-xml.php',
// Simple Google Sitemap XML (iTx Technologies)
'another-simple-xml-sitemap/another-simple-xml-sitemap.php',
// Another Simple XML Sitemap
'xml-maps/google-sitemap.php',
// Xml Sitemap (Jason Martens)
'google-xml-sitemap-generator-by-anton-dachauer/adachauer-google-xml-sitemap.php',
// Google XML Sitemap Generator by Anton Dachauer (Anton Dachauer)
'wp-xml-sitemap/wp-xml-sitemap.php',
// WP XML Sitemap (Team Vivacity)
'sitemap-generator-for-webmasters/sitemap.php',
// Sitemap Generator for Webmasters (iwebslogtech)
'xml-sitemap-xml-sitemapcouk/xmls.php',
// XML Sitemap - XML-Sitemap.co.uk (Simon Hancox)
'sewn-in-xml-sitemap/sewn-xml-sitemap.php',
// Sewn In XML Sitemap (jcow)
'rps-sitemap-generator/rps-sitemap-generator.php',
// RPS Sitemap Generator (redpixelstudios)
)
);
/**
* Overrides instance to set with this class as class
*
* @param string $class_name
*
* @return Yoast_Plugin_Conflict
*/
public static function get_instance( $class_name = __CLASS__ ) {
return parent::get_instance( $class_name );
}
}
/**
* After activating any plugin, this method will be executed by a hook.
*
* If the activated plugin is conflicting with ours a notice will be shown.
*
* @param string|bool $plugin
*
*/
public static function hook_check_for_plugin_conflicts( $plugin = false ) {
// The instance of itself
$instance = self::get_instance();
// Only add plugin as active plugin if $plugin isn't false
if ( $plugin ) {
// Because it's just activated
$instance->add_active_plugin( $instance->find_plugin_category( $plugin ), $plugin );
}
$plugin_sections = array(
/* translators: %s: 'Facebook' plugin name of possibly conflicting plugin with regard to creating OpenGraph output*/
'open_graph' => __( 'Both WordPress SEO by Yoast and %s create OpenGraph output, which might make Facebook, Twitter, LinkedIn and other social networks use the wrong texts and images when your pages are being shared.', 'wordpress-seo' ) . '<br/><br/>'
. '<a target="_blank" class="button" href="' . admin_url( 'admin.php?page=wpseo_social#top#facebook' ) . '">' . __( 'Configure WordPress SEO\'s OpenGraph settings', 'wordpress-seo' ) . '</a>' ,
/* translators: %s: 'Google XML Sitemaps' plugin name of possibly conflicting plugin with regard to the creation of sitemaps*/
'xml_sitemaps' => __( 'Both WordPress SEO by Yoast and %s can create XML sitemaps. Having two XML sitemaps is not beneficial for search engines, yet might slow down your site.', 'wordpress-seo' ) . '<br/><br/>'
. '<a target="_blank" class="button" href="' . admin_url( 'admin.php?page=wpseo_xml' ) . '">' . __( 'Configure WordPress SEO\'s XML Sitemap settings', 'wordpress-seo' ) . '</a>' ,
);
$instance->check_plugin_conflicts( $plugin_sections );
}
}
@@ -1,362 +1,306 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* This class handles the pointers used in the introduction tour.
*
* @todo Add an introductory pointer on the edit post page too.
*/
class WPSEO_Pointers {
if ( ! class_exists( 'WPSEO_Pointers' ) ) {
/**
* This class handles the pointers used in the introduction tour.
*
* @todo Add an introductory pointer on the edit post page too.
* @var object Instance of this class
*/
class WPSEO_Pointers {
public static $instance;
/**
* @var object Instance of this class
*/
public static $instance;
/**
* Class constructor.
*/
private function __construct() {
if ( current_user_can( 'manage_options' ) ) {
$options = get_option( 'wpseo' );
if ( $options['tracking_popup_done'] === false || $options['ignore_tour'] === false ) {
wp_enqueue_style( 'wp-pointer' );
wp_enqueue_script( 'jquery-ui' );
wp_enqueue_script( 'wp-pointer' );
wp_enqueue_script( 'utils' );
}
if ( $options['tracking_popup_done'] === false && ! isset( $_GET['allow_tracking'] ) ) {
add_action( 'admin_print_footer_scripts', array( $this, 'tracking_request' ) );
} elseif ( $options['ignore_tour'] === false ) {
add_action( 'admin_print_footer_scripts', array( $this, 'intro_tour' ) );
}
/**
* Class constructor.
*/
private function __construct() {
if ( current_user_can( 'manage_options' ) ) {
$options = get_option( 'wpseo' );
if ( $options['tracking_popup_done'] === false || $options['ignore_tour'] === false ) {
wp_enqueue_style( 'wp-pointer' );
wp_enqueue_script( 'jquery-ui' );
wp_enqueue_script( 'wp-pointer' );
wp_enqueue_script( 'utils' );
}
if ( $options['tracking_popup_done'] === false && ! isset( $_GET['allow_tracking'] ) ) {
add_action( 'admin_print_footer_scripts', array( $this, 'tracking_request' ) );
}
elseif ( $options['ignore_tour'] === false ) {
add_action( 'admin_print_footer_scripts', array( $this, 'intro_tour' ) );
}
}
}
/**
* Get the singleton instance of this class
*
* @return object
*/
public static function get_instance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
return self::$instance;
/**
* Get the singleton instance of this class
*
* @return object
*/
public static function get_instance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Shows a popup that asks for permission to allow tracking.
*/
function tracking_request() {
$id = '#wpadminbar';
$nonce = wp_create_nonce( 'wpseo_activate_tracking' );
$content = '<h3>' . __( 'Help improve WordPress SEO', 'wordpress-seo' ) . '</h3>';
$content .= '<p>' . __( 'You&#8217;ve just installed WordPress SEO by Yoast. Please helps us improve it by allowing us to gather anonymous usage stats so we know which configurations, plugins and themes to test with.', 'wordpress-seo' ) . '</p>';
$opt_arr = array(
/**
* Shows a popup that asks for permission to allow tracking.
*/
function tracking_request() {
$id = '#wpadminbar';
$nonce = wp_create_nonce( 'wpseo_activate_tracking' );
$content = '<h3>' . __( 'Help improve WordPress SEO', 'wordpress-seo' ) . '</h3>';
$content .= '<p>' . __( 'You&#8217;ve just installed WordPress SEO by Yoast. Please helps us improve it by allowing us to gather anonymous usage stats so we know which configurations, plugins and themes to test with.', 'wordpress-seo' ) . '</p>';
$opt_arr = array(
'content' => $content,
'position' => array( 'edge' => 'top', 'align' => 'center' )
);
$button_array = array(
'button1' => array(
'text' => __( 'Do not allow tracking', 'wordpress-seo' ),
'function' => 'wpseo_store_answer("no","' . $nonce . '")',
),
'button2' => array(
'text' => __( 'Allow tracking', 'wordpress-seo' ),
'function' => 'wpseo_store_answer("yes","' . $nonce . '")',
),
);
$this->print_scripts( $id, $opt_arr, $button_array );
}
/**
* Load the introduction tour
*/
function intro_tour() {
global $pagenow, $current_user;
$admin_pages = array(
'dashboard' => array(
'content' => '<h3>' . __( 'General settings', 'wordpress-seo' ) . '</h3><p>' . __( 'These are the General settings for WordPress SEO, here you can restart this tour or revert the WP SEO settings to default.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Tracking', 'wordpress-seo' ) . '</strong><br/>' . __( 'To provide you with the best experience possible, we need your help. Please enable tracking to help us gather anonymous usage data.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Tab: Your Info / Company Info', 'wordpress-seo' ) . '</strong><br/>' . __( 'Add some info here needed for Google\'s Knowledge Graph.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Tab: Webmaster Tools', 'wordpress-seo' ) . '</strong><br/>' . __( 'You can add the verification codes for the different Webmaster Tools programs here, we highly encourage you to check out both Google and Bing&#8217;s Webmaster Tools.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Tab: Security', 'wordpress-seo' ) . '</strong><br/>' . __( 'Determine who has access to the plugins advanced settings on the post edit screen.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'More WordPress SEO', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'There&#8217;s more to learn about WordPress &amp; SEO than just using this plugin. A great start is our article %1$sthe definitive guide to WordPress SEO%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/articles/wordpress-seo/#utm_source=wpseo_dashboard&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong style="font-size:150%;">' . __( 'Subscribe to our Newsletter', 'wordpress-seo' ) . '</strong><br/>'
. __( 'If you would like us to keep you up-to-date regarding WordPress SEO and other plugins by Yoast, subscribe to our newsletter:', 'wordpress-seo' ) . '</p>' .
'<form action="http://yoast.us1.list-manage1.com/subscribe/post?u=ffa93edfe21752c921f860358&amp;id=972f1c9122" method="post" id="newsletter-form" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">' .
'<p>' .
'<input style="margin: 5px; color:#666" name="EMAIL" value="' . esc_attr( $current_user->user_email ) . '" id="newsletter-email" placeholder="' . __( 'Email', 'wordpress-seo' ) . '"/>' .
'<input type="hidden" name="group" value="2"/>' .
'<button type="submit" class="button-primary">' . __( 'Subscribe', 'wordpress-seo' ) . '</button>' .
'</p></form>',
'next_page' => 'titles',
),
'titles' => array(
'content' => '<h3>' . __( 'Title &amp; Metas settings', 'wordpress-seo' ) . '</h3>' . '<p>' . __( 'This is where you set the titles and meta-information for all your post types, taxonomies, archives, special pages and for your homepage. The page is divided into different tabs. Make sure you check &#8217;em all out!', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Sitewide settings', 'wordpress-seo' ) . '</strong><br/>' . __( 'The first tab will show you site-wide settings for titles, normally you\'ll only need to change the Title Separator.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Templates and settings', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'Now click on the &#8216;%1$sPost Types%2$s&#8217;-tab, as this will be our example.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( admin_url( 'admin.php?page=wpseo_titles#top#post_types' ) ) . '">', '</a>' ) . '<br />' . __( 'The templates are built using variables. You can find all these variables in the help tab (in the top-right corner of the page). The settings allow you to set specific behavior for the post types.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Archives', 'wordpress-seo' ) . '</strong><br/>' . __( 'On the archives tab you can set templates for specific pages like author archives, search results and more.', 'wordpress-seo' )
. '<p><strong>' . __( 'Other', 'wordpress-seo' ) . '</strong><br/>' . __( 'On the Other tab you can change sitewide meta settings, like enable meta keywords.', 'wordpress-seo' ),
'next_page' => 'social',
'prev_page' => 'dashboard',
),
'social' => array(
'content' => '<h3>' . __( 'Social settings', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'Facebook', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'On this tab you can enable the %1$sFacebook Open Graph%2$s functionality from this plugin, as well as assign a Facebook user or Application to be the admin of your site, so you can view the Facebook insights.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/facebook-open-graph-protocol/#utm_source=wpseo_social&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p><p>' . __( 'The frontpage settings allow you to set meta-data for your homepage, whereas the default settings allow you to set a fallback for all posts/pages without images. ', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Twitter', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'With %1$sTwitter Cards%2$s, you can attach rich photos, videos and media experience to tweets that drive traffic to your website. Simply check the box, sign up for the service, and users who Tweet links to your content will have a &#8220;Card&#8221; added to the tweet that&#8217;s visible to all of their followers.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/twitter-cards/#utm_source=wpseo_social&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Pinterest', 'wordpress-seo' ) . '</strong><br/>' . __( 'On this tab you can verify your site with Pinterest and enter your Pinterest account.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Google+', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'This tab allows you to add specific post meta data for Google+. And if you have a Google+ page for your business, add that URL here and link it on your %1$sGoogle+%2$s page&#8217;s about page.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://plus.google.com/' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Other', 'wordpress-seo' ) . '</strong><br/>' . __( 'On this tab you can enter some more of your social accounts, mostly used for Google\'s Knowledge Graph.', 'wordpress-seo' ) . '</p>',
'next_page' => 'xml',
'prev_page' => 'titles',
),
'xml' => array(
'content' => '<h3>' . __( 'XML Sitemaps', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'What are XML sitemaps?', 'wordpress-seo' ) . '</strong><br/>' . __( 'A Sitemap is an XML file that lists the URLs for a site. It allows webmasters to include additional information about each URL: when it was last updated, how often it changes, and how important it is in relation to other URLs in the site. This allows search engines to crawl the site more intelligently.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'What does the plugin do with XML Sitemaps?', 'wordpress-seo' ) . '</strong><br/>' . __( 'This plugin adds XML sitemaps to your site. The sitemaps are automatically updated when you publish a new post, page or custom post and Google and Bing will be automatically notified.', 'wordpress-seo' ) . '</p><p>' . __( 'If you want to exclude certain post types and/or taxonomies, you can also set that on this page.', 'wordpress-seo' ) . '</p><p>' . __( 'Is your webserver low on memory? Decrease the entries per sitemap (default: 1000) to reduce load.', 'wordpress-seo' ) . '</p>',
'next_page' => 'advanced',
'prev_page' => 'social',
),
'advanced' => array(
'content' => '<h3>' . __( 'Advanced Settings', 'wordpress-seo' ) . '</h3><p>' . __( 'All of the options on these tabs are for advanced users only, if you don&#8217;t know whether you should check any, don&#8217;t touch them.', 'wordpress-seo' ) . '</p>',
'next_page' => 'licenses',
'prev_page' => 'xml',
),
'licenses' => array(
'content' => '<h3>' . __( 'Extensions and Licenses', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'Extensions', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'The powerful functions of WordPress SEO can be extended with %1$sYoast premium plugins%2$s. These premium plugins require the installation of WordPress SEO or WordPress SEO Premium and add specific functionality. You can read all about the Yoast Premium Plugins %1$shere%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/wordpress/plugins/#utm_source=wpseo_licenses&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Licenses', 'wordpress-seo' ) . '</strong><br/>' . __( 'Once you&#8217;ve purchased WordPress SEO Premium or any other premium Yoast plugin, you&#8217;ll have to enter a license key. You can do so on the Licenses-tab. Once you&#8217;ve activated your premium plugin, you can use all its powerful features.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Like this plugin?', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'So, we&#8217;ve come to the end of the tour. If you like the plugin, please %srate it 5 stars on WordPress.org%s!', 'wordpress-seo' ), '<a target="_blank" href="https://wordpress.org/plugins/wordpress-seo/">', '</a>' ) . '</p>'
. '<p>' . sprintf( __( 'Thank you for using our plugin and good luck with your SEO!<br/><br/>Best,<br/>Team Yoast - %1$sYoast.com%2$s', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/#utm_source=wpseo_licenses&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>',
'prev_page' => 'advanced',
),
);
$page = filter_input( INPUT_GET, 'page' );
$page = str_replace( 'wpseo_', '', $page );
$button_array = array(
'button1' => array(
'text' => __( 'Close', 'wordpress-seo' ),
'function' => '',
),
);
$opt_arr = array();
$id = '#wpseo-title';
if ( 'admin.php' != $pagenow || ! array_key_exists( $page, $admin_pages ) ) {
$id = 'li.toplevel_page_wpseo_dashboard';
$content = '
<h3>' . __( 'Congratulations!', 'wordpress-seo' ) . '</h3>
<p>' . __( 'You&#8217;ve just installed WordPress SEO by Yoast! Click &#8220;Start Tour&#8221; to view a quick introduction of this plugin&#8217;s core functionality.', 'wordpress-seo' ) . '</p>';
$opt_arr = array(
'content' => $content,
'position' => array( 'edge' => 'top', 'align' => 'center' )
'position' => array( 'edge' => 'bottom', 'align' => 'center' )
);
$button_array = array(
'button1' => array(
'text' => __( 'Do not allow tracking', 'wordpress-seo' ),
'function' => 'wpseo_store_answer("no","' . $nonce . '")',
),
'button2' => array(
'text' => __( 'Allow tracking', 'wordpress-seo' ),
'function' => 'wpseo_store_answer("yes","' . $nonce . '")',
),
);
$this->print_scripts( $id, $opt_arr, $button_array );
$button_array['button2']['text'] = __( 'Start Tour', 'wordpress-seo' );
$button_array['button2']['function'] = sprintf( 'document.location="%s";', admin_url( 'admin.php?page=wpseo_dashboard' ) );
}
/**
* Load the introduction tour
*/
function intro_tour() {
global $pagenow, $current_user;
// @FIXME: Links to tabs only work with target="_blank" and thus open in a new window
$adminpages = array(
'wpseo_dashboard' => array(
'content' => '<h3>' . __( 'Dashboard', 'wordpress-seo' ) . '</h3><p>' . __( 'This is the WordPress SEO Dashboard, here you can restart this tour or revert the WP SEO settings to default.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'More WordPress SEO', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'There&#8217;s more to learn about WordPress &amp; SEO than just using this plugin. A great start is our article %1$sthe definitive guide to WordPress SEO%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/articles/wordpress-seo/#utm_source=wpseo_dashboard&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Tracking', 'wordpress-seo' ) . '</strong><br/>' . __( 'To provide you with the best experience possible, we need your help. Please enable tracking to help us gather anonymous usage data.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Webmaster Tools', 'wordpress-seo' ) . '</strong><br/>' . __( 'You can also add the verification codes for the different Webmaster Tools programs here, we highly encourage you to check out both Google and Bing&#8217;s Webmaster Tools.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'WordPress SEO Tour', 'wordpress-seo' ) . '</strong><br/>' . __( 'This tour will show you around in the plugin, to give you a general overview of the plugin.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Newsletter', 'wordpress-seo' ) . '</strong><br/>' .
__( 'If you would like to us to keep you up-to-date regarding WordPress SEO and other plugins by Yoast, subscribe to our newsletter:', 'wordpress-seo' ) . '</p>' .
'<form action="http://yoast.us1.list-manage1.com/subscribe/post?u=ffa93edfe21752c921f860358&amp;id=972f1c9122" method="post" id="newsletter-form" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">' .
'<p>' .
'<label for="newsletter-email">' . __( 'Email', 'wordpress-seo' ) . ':</label> <input style="margin: 5px; color:#666" name="EMAIL" value="' . esc_attr( $current_user->user_email ) . '" id="newsletter-email" placeholder="' . __( 'Email', 'wordpress-seo' ) . '"/><br/>' .
'<input type="hidden" name="group" value="2"/>' .
'<button type="submit" class="button-primary">' . __( 'Subscribe', 'wordpress-seo' ) . '</button>' .
'</p></form>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_titles' ) . '";',
'position' => array( 'edge' => 'top', 'align' => 'center' ),
),
'wpseo_titles' => array(
'content' => '<h3>' . __( 'Title &amp; Metas settings', 'wordpress-seo' ) . '</h3>' . '<p>' . __( 'This is where you set the titles and meta-information for all your post types, taxonomies, archives, special pages and for your homepage. The page is divided into different tabs. Make sure you check &#8217;em all out!', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Sitewide settings', 'wordpress-seo' ) . '</strong><br/>' . __( 'The first tab will show you site-wide settings. You can also set some settings for the entire site here to add specific meta tags or to remove some unneeded cruft.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Templates and settings', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'Now click on the &#8216;%1$sPost Types%2$s&#8217;-tab, as this will be our example.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( admin_url( 'admin.php?page=wpseo_titles#top#post_types' ) ) . '">', '</a>' ) . '<br />' . __( 'The templates are built using variables. You can find all these variables in the help tab (in the top-right corner of the page). The settings allow you to set specific behavior for the post types.', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_social' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_dashboard' ) . '";',
),
'wpseo_social' => array(
'content' => '<h3>' . __( 'Social settings', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'Facebook', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'On this tab you can enable the %1$sFacebook Open Graph%2$s functionality from this plugin, as well as assign a Facebook user or Application to be the admin of your site, so you can view the Facebook insights.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/facebook-open-graph-protocol/#utm_source=wpseo_social&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p><p>' . __( 'The frontpage settings allow you to set meta-data for your homepage, whereas the default settings allow you to set a fallback for all posts/pages without images. ', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Twitter', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'With %1$sTwitter Cards%2$s, you can attach rich photos, videos and media experience to tweets that drive traffic to your website. Simply check the box, sign up for the service, and users who Tweet links to your content will have a &#8220;Card&#8221; added to the tweet that&#8217;s visible to all of their followers.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/twitter-cards/#utm_source=wpseo_social&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Google+', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'This tab allows you to add specific post meta data for Google+. And if you have a Google+ page for your business, add that URL here and link it on your %1$sGoogle+%2$s page&#8217;s about page.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://plus.google.com/' ) . '">', '</a>' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_xml' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_titles' ) . '";',
),
'wpseo_xml' => array(
'content' => '<h3>' . __( 'XML Sitemaps', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'What are XML sitemaps?', 'wordpress-seo' ) . '</strong><br/>' . __( 'A Sitemap is an XML file that lists the URLs for a site. It allows webmasters to include additional information about each URL: when it was last updated, how often it changes, and how important it is in relation to other URLs in the site. This allows search engines to crawl the site more intelligently.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'What does the plugin do with XML Sitemaps?', 'wordpress-seo' ) . '</strong><br/>' . __( 'This plugin adds XML sitemaps to your site. The sitemaps are automatically updated when you publish a new post, page or custom post and Google and Bing will be automatically notified. You can also have the plugin automatically notify Yahoo! and Ask.com.', 'wordpress-seo' ) . '</p><p>' . __( 'If you want to exclude certain post types and/or taxonomies, you can also set that on this page.', 'wordpress-seo' ) . '</p><p>' . __( 'Is your webserver low on memory? Decrease the entries per sitemap (default: 1000) to reduce load.', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_permalinks' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_social' ) . '";',
),
'wpseo_permalinks' => array(
'content' => '<h3>' . __( 'Permalink Settings', 'wordpress-seo' ) . '</h3><p>' . __( 'All of the options here are for advanced users only, if you don&#8217;t know whether you should check any, don&#8217;t touch them.', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_internal-links' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_xml' ) . '";',
),
'wpseo_internal-links' => array(
'content' => '<h3>' . __( 'Breadcrumbs Settings', 'wordpress-seo' ) . '</h3><p>' . sprintf( __( 'If your theme supports my breadcrumbs, as all Genesis and WooThemes themes as well as a couple of other ones do, you can change the settings for those here. If you want to modify your theme to support them, %sfollow these instructions%s.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/wordpress/plugins/breadcrumbs/#utm_source=wpseo_permalinks&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_rss' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_permalinks' ) . '";',
),
'wpseo_rss' => array(
'content' => '<h3>' . __( 'RSS Settings', 'wordpress-seo' ) . '</h3><p>' . __( 'This incredibly powerful function allows you to add content to the beginning and end of your posts in your RSS feed. This helps you gain links from people who steal your content!', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_import' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_internal-links' ) . '";',
),
'wpseo_import' => array(
'content' => '<h3>' . esc_html__( 'Import & Export', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'Import from other (SEO) plugins', 'wordpress-seo' ) . '</strong><br/>' . __( 'We can imagine that you switch from another SEO plugin to WordPress SEO. If you just did, you can use these options to transfer your SEO-data. If you were using one of my older plugins like Robots Meta &amp; RSS Footer, you can import the settings here too.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Other imports', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'If you&#8217;re using one of our premium plugins, such as %1$sLocal SEO%2$s, you can also find specific import-options for that plugin here.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/wordpress/plugins/local-seo/#utm_source=wpseo_import&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Export', 'wordpress-seo' ) . '</strong><br/>' . __( 'If you have multiple blogs and you&#8217;re happy with how you&#8217;ve configured this blog, you can export the settings and import them on another blog so you don&#8217;t have to go through this process twice!', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . network_admin_url( 'admin.php?page=wpseo_bulk-editor' ) . '";', // will auto-use admin_url if not on multi-site
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_rss' ) . '";',
),
'wpseo_bulk-editor' => array(
'content' => '<h3>' . __( 'Bulk Editor', 'wordpress-seo' ) . '</h3><p>' . __( 'This page lets you view and edit the titles and meta descriptions of all posts and pages on your site. This allows you to edit the title or meta description of all your pages in one place, rather than having to edit each individual page.', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_files' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_import' ) . '";',
),
'wpseo_files' => array(
'content' => '<h3>' . __( 'File Editor', 'wordpress-seo' ) . '</h3><p>' . __( 'Here you can edit the .htaccess and robots.txt files, two of the most powerful files in your WordPress install, if your WordPress installation has write-access to the files. But please, only touch these files if you know what you&#8217;re doing!', 'wordpress-seo' ) . '</p>',
'next' => __( 'Next', 'wordpress-seo' ),
'next_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_licenses' ) . '";',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_bulk-editor' ) . '";',
),
'wpseo_licenses' => array(
'content' => '<h3>' . __( 'Extensions and Licenses', 'wordpress-seo' ) . '</h3>'
. '<p><strong>' . __( 'Extensions', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'The powerful functions of WordPress SEO can be extended with %1$sYoast premium plugins%2$s. These premium plugins require the installation of WordPress SEO or WordPress SEO Premium and add specific functionality. You can read all about the Yoast Premium Plugins on %1$shttp://yoast.com/wordpress/plugins/%2$s.', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/wordpress/plugins/#utm_source=wpseo_licenses&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>'
. '<p><strong>' . __( 'Licenses', 'wordpress-seo' ) . '</strong><br/>' . __( 'Once you&#8217;ve purchased WordPress SEO Premium or any other premium Yoast plugin, you&#8217;ll have to enter a license key. You can do so on the Licenses-tab. Once you&#8217;ve activated your premium plugin, you can use all its powerful features.', 'wordpress-seo' ) . '</p>'
. '<p><strong>' . __( 'Like this plugin?', 'wordpress-seo' ) . '</strong><br/>' . sprintf( __( 'So, we&#8217;ve come to the end of the tour. If you like the plugin, please %srate it 5 stars on WordPress.org%s!', 'wordpress-seo' ), '<a target="_blank" href="https://wordpress.org/plugins/wordpress-seo/">', '</a>' ) . '</p>'
. '<p>' . sprintf( __( 'Thank you for using my plugin and good luck with your SEO!<br/><br/>Best,<br/>Team Yoast - %1$sYoast.com%2$s', 'wordpress-seo' ), '<a target="_blank" href="' . esc_url( 'https://yoast.com/#utm_source=wpseo_licenses&utm_medium=wpseo_tour&utm_campaign=tour' ) . '">', '</a>' ) . '</p>',
'prev' => __( 'Previous', 'wordpress-seo' ),
'prev_function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_files' ) . '";',
),
);
// Skip tour about wpseo_files page if file editing is disallowed or if the site is a multisite and the current user isn't a superadmin
if ( false === wpseo_allow_system_file_edit() ) {
unset( $adminpages['wpseo_files'] );
$adminpages['wpseo_bulk-editor']['function'] = 'window.location="' . admin_url( 'admin.php?page=wpseo_licenses' ) . '";';
}
$page = '';
if ( isset( $_GET['page'] ) ) {
$page = $_GET['page'];
}
$button_array = array(
'button1' => array(
'text' => __( 'Close', 'wordpress-seo' ),
'function' => '',
)
);
$opt_arr = array();
$id = '#wpseo-title';
if ( 'admin.php' != $pagenow || ! array_key_exists( $page, $adminpages ) ) {
$id = 'li.toplevel_page_wpseo_dashboard';
$content = '<h3>' . __( 'Congratulations!', 'wordpress-seo' ) . '</h3>';
$content .= '<p>' . __( 'You&#8217;ve just installed WordPress SEO by Yoast! Click &#8220;Start Tour&#8221; to view a quick introduction of this plugin&#8217;s core functionality.', 'wordpress-seo' ) . '</p>';
$opt_arr = array(
'content' => $content,
'position' => array( 'edge' => 'bottom', 'align' => 'center' )
else {
if ( '' != $page && in_array( $page, array_keys( $admin_pages ) ) ) {
$align = ( is_rtl() ) ? 'left' : 'right';
$default_position = array(
'edge' => 'top',
'align' => $align,
);
$button_array['button2']['text'] = __( 'Start Tour', 'wordpress-seo' );
$button_array['button2']['function'] = 'document.location="' . admin_url( 'admin.php?page=wpseo_dashboard' ) . '";';
} else {
if ( '' != $page && in_array( $page, array_keys( $adminpages ) ) ) {
$align = ( is_rtl() ) ? 'left' : 'right';
$opt_arr = array(
'content' => $adminpages[$page]['content'],
'position' => ( isset ( $adminpages[$page]['position'] ) ) ? ( $adminpages[$page]['position'] ) : array( 'edge' => 'top', 'align' => $align ),
'pointerWidth' => 450,
$opt_arr = array(
'content' => $admin_pages[ $page ]['content'],
'position' => ( isset ( $admin_pages[ $page ]['position'] ) ) ? ( $admin_pages[ $page ]['position'] ) : $default_position,
'pointerWidth' => 450,
);
if ( isset( $admin_pages[ $page ]['next_page'] ) ) {
$button_array['button2'] = array(
'text' => __( 'Next', 'wordpress-seo' ),
'function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_' . $admin_pages[ $page ]['next_page'] ) . '";',
);
}
if ( isset( $admin_pages[ $page ]['prev_page'] ) ) {
$button_array['button3'] = array(
'text' => __( 'Previous', 'wordpress-seo' ),
'function' => 'window.location="' . admin_url( 'admin.php?page=wpseo_' . $admin_pages[ $page ]['prev_page'] ) . '";',
);
if ( isset( $adminpages[$page]['next'] ) && isset( $adminpages[$page]['next_function'] ) ) {
$button_array['button2'] = array(
'text' => $adminpages[$page]['next'],
'function' => $adminpages[$page]['next_function'],
);
}
if ( isset( $adminpages[$page]['prev'] ) && isset( $adminpages[$page]['prev_function'] ) ) {
$button_array['button3'] = array(
'text' => $adminpages[$page]['prev'],
'function' => $adminpages[$page]['prev_function'],
);
}
}
}
$this->print_scripts( $id, $opt_arr, $button_array );
}
$this->print_scripts( $id, $opt_arr, $button_array );
}
/**
* Prints the pointer script
*
* @param string $selector The CSS selector the pointer is attached to.
* @param array $options The options for the pointer.
* @param array $button_array The options for the buttons.
*/
function print_scripts( $selector, $options, $button_array ) {
$button_array_defaults = array(
'button1' => array(
'text' => false,
'function' => '',
),
'button2' => array(
'text' => false,
'function' => '',
),
'button3' => array(
'text' => false,
'function' => '',
),
);
$button_array = wp_parse_args( $button_array, $button_array_defaults );
?>
<script type="text/javascript">
//<![CDATA[
(function ($) {
// Don't show the tour on screens with an effective width smaller than 1024px or an effective height smaller than 768px.
if (jQuery(window).width() < 1024 || jQuery(window).availWidth < 1024 ) {
return;
}
var wpseo_pointer_options = <?php echo json_encode( $options ); ?>, setup;
/**
* Prints the pointer script
*
* @param string $selector The CSS selector the pointer is attached to.
* @param array $options The options for the pointer.
* @param array $button_array The options for the buttons.
*/
function print_scripts( $selector, $options, $button_array ) {
$button_array_defaults = array(
'button1' => array(
'text' => false,
'function' => '',
),
'button2' => array(
'text' => false,
'function' => '',
),
'button3' => array(
'text' => false,
'function' => '',
),
);
$button_array = wp_parse_args( $button_array, $button_array_defaults );
?>
<script type="text/javascript">
//<![CDATA[
(function ($) {
// Don't show the tour on screens with an effective width smaller than 1024px or an effective height smaller than 768px.
if (jQuery(window).width() < 1024 || jQuery(window).availWidth < 1024) {
return;
}
function wpseo_store_answer(input, nonce) {
var wpseo_tracking_data = {
action : 'wpseo_allow_tracking',
allow_tracking: input,
nonce : nonce
};
jQuery.post(ajaxurl, wpseo_tracking_data, function () {
jQuery('#wp-pointer-0').remove();
});
}
var wpseo_pointer_options = <?php echo json_encode( $options ); ?>, setup;
wpseo_pointer_options = $.extend(wpseo_pointer_options, {
buttons: function (event, t) {
var button = jQuery('<a id="pointer-close" style="margin:0 5px;" class="button-secondary">' + '<?php echo $button_array['button1']['text']; ?>' + '</a>');
button.bind('click.pointer', function () {
t.element.pointer('close');
});
return button;
},
close : function () {
}
});
setup = function () {
$('<?php echo $selector; ?>').pointer(wpseo_pointer_options).pointer('open');
<?php if ( $button_array['button2']['text'] ) { ?>
jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + '<?php echo $button_array['button2']['text']; ?>' + '</a>');
jQuery('#pointer-primary').click(function () {
<?php echo $button_array['button2']['function']; ?>
});
<?php if ( $button_array['button3']['text'] ) { ?>
jQuery('#pointer-primary').after('<a id="pointer-ternary" style="float: left;" class="button-secondary">' + '<?php echo $button_array['button3']['text']; ?>' + '</a>');
jQuery('#pointer-ternary').click(function () {
<?php echo $button_array['button3']['function']; ?>
});
<?php } ?>
jQuery('#pointer-close').click(function () {
<?php if ( $button_array['button1']['function'] == '' ) { ?>
wpseo_setIgnore("tour", "wp-pointer-0", "<?php echo esc_js( wp_create_nonce( 'wpseo-ignore' ) ); ?>");
<?php } else { ?>
<?php echo $button_array['button1']['function']; ?>
<?php } ?>
});
<?php } else if ( $button_array['button3']['text'] ) { ?>
jQuery('#pointer-close').after('<a id="pointer-ternary" style="float: left;" class="button-secondary">' + '<?php echo $button_array['button3']['text']; ?>' + '</a>');
jQuery('#pointer-ternary').click(function () {
<?php echo $button_array['button3']['function']; ?>
});
<?php } ?>
function wpseo_store_answer(input, nonce) {
var wpseo_tracking_data = {
action: 'wpseo_allow_tracking',
allow_tracking: input,
nonce: nonce
};
jQuery.post(ajaxurl, wpseo_tracking_data, function () {
jQuery('#wp-pointer-0').remove();
});
}
if (wpseo_pointer_options.position && wpseo_pointer_options.position.defer_loading)
$(window).bind('load.wp-pointers', setup);
else
$(document).ready(setup);
})(jQuery);
//]]>
</script>
<?php
}
wpseo_pointer_options = $.extend(wpseo_pointer_options, {
buttons: function (event, t) {
var button = jQuery('<a id="pointer-close" style="margin:0 5px;" class="button-secondary">' + '<?php echo $button_array['button1']['text']; ?>' + '</a>');
button.bind('click.pointer', function () {
t.element.pointer('close');
});
return button;
},
close: function () {
}
});
setup = function () {
$('<?php echo $selector; ?>').pointer(wpseo_pointer_options).pointer('open');
<?php if ( $button_array['button2']['text'] ) : ?>
jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + '<?php echo $button_array['button2']['text']; ?>' + '</a>');
jQuery('#pointer-primary').click(function () {
<?php echo $button_array['button2']['function']; ?>
});
<?php if ( $button_array['button3']['text'] ) { ?>
jQuery('#pointer-primary').after('<a id="pointer-ternary" style="float: left;" class="button-secondary">' + '<?php echo $button_array['button3']['text']; ?>' + '</a>');
jQuery('#pointer-ternary').click(function () {
<?php echo $button_array['button3']['function']; ?>
});
<?php } ?>
jQuery('#pointer-close').click(function () {
<?php if ( $button_array['button1']['function'] == '' ) : ?>
wpseo_setIgnore("tour", "wp-pointer-0", "<?php echo esc_js( wp_create_nonce( 'wpseo-ignore' ) ); ?>");
<?php else : ?>
<?php echo $button_array['button1']['function']; ?>
<?php endif; ?>
});
<?php elseif ( $button_array['button3']['text'] ) : ?>
jQuery('#pointer-close').after('<a id="pointer-ternary" style="float: left;" class="button-secondary">' + '<?php echo $button_array['button3']['text']; ?>' + '</a>');
jQuery('#pointer-ternary').click(function () {
<?php echo $button_array['button3']['function']; ?>
});
<?php endif; ?>
};
if (wpseo_pointer_options.position && wpseo_pointer_options.position.defer_loading)
$(window).bind('load.wp-pointers', setup);
else
$(document).ready(setup);
})(jQuery);
//]]>
</script>
<?php
}
/**
* Load a tiny bit of CSS in the head
*
* @deprecated 1.5.0, now handled by css
*/
function admin_head() {
_deprecated_function( __METHOD__, 'WPSEO 1.5.0' );
/**
* Load a tiny bit of CSS in the head
*
* @deprecated 1.5.0, now handled by css
*/
function admin_head() {
_deprecated_function( __METHOD__, 'WPSEO 1.5.0' );
return;
}
return;
}
} /* End of class */
} /* End of class-exists wrapper */
} /* End of class */
@@ -1,89 +1,88 @@
<?php
/**
* @package XML_Sitemaps
* @package WPSEO\Admin\XML Sitemaps
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Class that handles the Admin side of XML sitemaps
*/
class WPSEO_Sitemaps_Admin {
if ( ! class_exists( 'WPSEO_Sitemaps_Admin' ) ) {
/**
* Class that handles the Admin side of XML sitemaps
* Class constructor
*/
class WPSEO_Sitemaps_Admin {
function __construct() {
add_action( 'transition_post_status', array( $this, 'status_transition' ), 10, 3 );
add_action( 'admin_init', array( $this, 'delete_sitemaps' ) );
}
/**
* Class constructor
*/
function __construct() {
add_action( 'transition_post_status', array( $this, 'status_transition' ), 10, 3 );
add_action( 'admin_init', array( $this, 'delete_sitemaps' ) );
}
/**
* Find sitemaps residing on disk as they will block our rewrite.
*
* @todo issue #561 https://github.com/Yoast/wordpress-seo/issues/561
*/
function delete_sitemaps() {
$options = WPSEO_Options::get_all();
if ( $options['enablexmlsitemap'] === true ) {
/**
* Find sitemaps residing on disk as they will block our rewrite.
*
* @todo issue #561 https://github.com/Yoast/wordpress-seo/issues/561
*/
function delete_sitemaps() {
$options = WPSEO_Options::get_all();
if ( $options['enablexmlsitemap'] === true ) {
$file_to_check_for = array(
// ABSPATH . 'sitemap.xml',
// ABSPATH . 'sitemap.xslt',
// ABSPATH . 'sitemap.xsl',
ABSPATH . 'sitemap_index.xml',
);
$file_to_check_for = array(
//ABSPATH . 'sitemap.xml',
//ABSPATH . 'sitemap.xslt',
//ABSPATH . 'sitemap.xsl',
ABSPATH . 'sitemap_index.xml',
);
$new_files_found = false;
$new_files_found = false;
foreach ( $file_to_check_for as $file ) {
if ( ( $options['blocking_files'] === array() || ( $options['blocking_files'] !== array() && in_array( $file, $options['blocking_files'] ) === false ) ) && file_exists( $file ) ) {
$options['blocking_files'][] = $file;
$new_files_found = true;
}
}
if ( $new_files_found === true ) {
update_option( 'wpseo', $options );
foreach ( $file_to_check_for as $file ) {
if ( ( $options['blocking_files'] === array() || ( $options['blocking_files'] !== array() && in_array( $file, $options['blocking_files'] ) === false ) ) && file_exists( $file ) ) {
$options['blocking_files'][] = $file;
$new_files_found = true;
}
}
unset( $file );
if ( $new_files_found === true ) {
update_option( 'wpseo', $options );
}
}
}
/**
* Hooked into transition_post_status. Will initiate search engine pings
* if the post is being published, is a post type that a sitemap is built for
* and is a post that is included in sitemaps.
*/
function status_transition( $new_status, $old_status, $post ) {
if ( $new_status != 'publish' ) {
return;
/**
* Hooked into transition_post_status. Will initiate search engine pings
* if the post is being published, is a post type that a sitemap is built for
* and is a post that is included in sitemaps.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param \WP_Post $post Post object.
*/
function status_transition( $new_status, $old_status, $post ) {
if ( $new_status != 'publish' ) {
return;
}
wp_cache_delete( 'lastpostmodified:gmt:' . $post->post_type, 'timeinfo' ); // #17455
$options = WPSEO_Options::get_all();
if ( isset( $options[ 'post_types-' . $post->post_type . '-not_in_sitemap' ] ) && $options[ 'post_types-' . $post->post_type . '-not_in_sitemap' ] === true ) {
return;
}
if ( WP_CACHE ) {
wp_schedule_single_event( ( time() + 300 ), 'wpseo_hit_sitemap_index' );
}
// Allow the pinging to happen slightly after the hit sitemap index so the sitemap is fully regenerated when the ping happens.
if ( WPSEO_Meta::get_value( 'sitemap-include', $post->ID ) !== 'never' ) {
if ( defined( 'YOAST_SEO_PING_IMMEDIATELY' ) && YOAST_SEO_PING_IMMEDIATELY ) {
wpseo_ping_search_engines();
}
wp_cache_delete( 'lastpostmodified:gmt:' . $post->post_type, 'timeinfo' ); // #17455
$options = WPSEO_Options::get_all();
if ( isset( $options[ 'post_types-' . $post->post_type . '-not_in_sitemap' ] ) && $options[ 'post_types-' . $post->post_type . '-not_in_sitemap' ] === true ) {
return;
}
if ( WP_CACHE ) {
wp_schedule_single_event( time() + 300, 'wpseo_hit_sitemap_index' );
}
// Allow the pinging to happen slightly after the hit sitemap index so the sitemap is fully regenerated when the ping happens.
if ( WPSEO_Meta::get_value( 'sitemap-include', $post->ID ) !== 'never' ) {
if ( defined( 'YOAST_SEO_PING_IMMEDIATELY' ) && YOAST_SEO_PING_IMMEDIATELY ) {
wpseo_ping_search_engines();
}
else {
wp_schedule_single_event( ( time() + 300 ), 'wpseo_ping_search_engines' );
}
else {
wp_schedule_single_event( ( time() + 300 ), 'wpseo_ping_search_engines' );
}
}
} /* End of class */
}
} /* End of class */
} /* End of class-exists wrapper */
@@ -1,156 +1,163 @@
<?php
if ( ! class_exists( 'WPSEO_Snippet_Preview' ) ) {
/**
* @package WPSEO\Admin
* @since 1.6.2
*/
/**
* class WPSEO_Snippet_Preview
*
* Generates a Google Search snippet preview.
*
* Takes a $post, $title and $description
*
*/
class WPSEO_Snippet_Preview {
/**
* class WPSEO_Snippet_Preview
*
* Generates a Google Search snippet preview.
*
* Takes a $post, $title and $description
*
* @var string The dynamically generated html for the snippet preview.
*/
class WPSEO_Snippet_Preview {
/**
* @var string The dynamically generated html for the snippet preview.
*/
protected $content;
protected $content;
/**
* @var array The WPSEO options.
*/
protected $options;
/**
* @var array The WPSEO options.
*/
protected $options;
/**
* @var object The post for which we want to generate the snippet preview.
*/
protected $post;
/**
* @var object The post for which we want to generate the snippet preview.
*/
protected $post;
/**
* @var string The title that is shown in the snippet.
*/
protected $title;
/**
* @var string The title that is shown in the snippet.
*/
protected $title;
/**
* @var string The description that is shown in the snippet.
*/
protected $description;
/**
* @var string The description that is shown in the snippet.
*/
protected $description;
/**
* @var string The date that is shown at the beginning of the description in the snippet.
*/
protected $date = '';
/**
* @var string The date that is shown at the beginning of the description in the snippet.
*/
protected $date = '';
/**
* @var string The url that is shown in the snippet.
*/
protected $url;
/**
* @var string The url that is shown in the snippet.
*/
protected $url;
/**
* @var string The slug of the url that is shown in the snippet.
*/
protected $slug = '';
/**
* @var string The slug of the url that is shown in the snippet.
*/
protected $slug = '';
/**
* Generates the html for the snippet preview containing dynamically generated text components.
* Those components are included as properties which are set in the constructor.
*
* @param object $post
* @param string $title
* @param string $description
*/
public function __construct( $post, $title, $description ) {
$this->options = WPSEO_Options::get_all();
$this->post = $post;
$this->title = esc_html( $title );
$this->description = esc_html( $description );
/**
* Generates the html for the snippet preview containing dynamically generated text components.
* Those components are included as properties which are set in the constructor.
*
* @param object $post
* @param string $title
* @param string $description
*/
public function __construct( $post, $title, $description ) {
$this->options = WPSEO_Options::get_all();
$this->post = $post;
$this->title = esc_html( $title );
$this->description = esc_html( $description );
$this->set_date();
$this->set_url();
$this->set_content();
$this->set_date();
$this->set_url();
$this->set_content();
}
/**
* Getter for $this->content
* @return string html for snippet preview
*/
public function get_content() {
return $this->content;
}
/**
* Sets date if available
*/
protected function set_date() {
if ( is_object( $this->post ) && isset( $this->options[ 'showdate-' . $this->post->post_type ] ) && $this->options[ 'showdate-' . $this->post->post_type ] === true ) {
$date = $this->get_post_date();
$this->date = '<span class="date">' . $date . ' - </span>';
}
}
/**
* Retrieves a post date when post is published, or return current date when it's not.
*
* @return string
*/
protected function get_post_date() {
if ( isset( $this->post->post_date ) && $this->post->post_status == 'publish' ) {
$date = date_i18n( 'j M Y', strtotime( $this->post->post_date ) );
}
else {
$date = date_i18n( 'j M Y' );
}
/**
* Getter for $this->content
* @return string html for snippet preview
*/
public function get_content() {
return $this->content;
return (string) $date;
}
/**
* Generates the url that is displayed in the snippet preview.
*/
protected function set_url() {
$this->url = str_replace( array( 'http://', 'https://' ), '', get_bloginfo( 'url' ) ) . '/';
$this->set_slug();
}
/**
* Sets the slug and adds it to the url if the post has been published and the post name exists.
*
* If the post is set to be the homepage the slug is also not included.
*/
protected function set_slug() {
$frontpage_post_id = (int) ( get_option( 'page_on_front' ) );
if ( is_object( $this->post ) && isset( $this->post->post_name ) && $this->post->post_name !== '' && $this->post->ID !== $frontpage_post_id ) {
$this->slug = sanitize_title( $this->title );
$this->url .= esc_html( $this->slug );
}
}
/**
* Sets date if available
*/
protected function set_date() {
if ( is_object( $this->post ) && isset( $this->options['showdate-' . $this->post->post_type] ) && $this->options['showdate-' . $this->post->post_type] === true ) {
$date = $this->get_post_date();
$this->date = '<span class="date">' . $date . ' - </span>';
}
}
/**
* Retrieves a post date when post is published, or return current date when it's not.
*
* @param object $post Post to retrieve the date for.
*
* @return string
*/
protected function get_post_date() {
if ( isset( $this->post->post_date ) && $this->post->post_status == 'publish' ) {
$date = date_i18n( 'j M Y', strtotime( $this->post->post_date ) );
} else {
$date = date_i18n( 'j M Y' );
}
return (string) $date;
}
/**
* Generates the url that is displayed in the snippet preview.
*/
protected function set_url() {
$this->url = str_replace( array( 'http://', 'https://' ), '', get_bloginfo( 'url' ) ) . '/';
$this->set_slug();
}
/**
* Sets the slug and adds it to the url if the post has been published and the post name exists.
*
* If the post is set to be the homepage the slug is also not included.
*/
protected function set_slug() {
$frontpage_post_id = (int) ( get_option( 'page_on_front' ) );
if ( is_object( $this->post ) && isset( $this->post->post_name ) && $this->post->post_name !== '' && $this->post->ID !== $frontpage_post_id ) {
$this->slug = sanitize_title( $this->title );
$this->url .= esc_html( $this->slug );
}
}
/**
* Generates the html for the snippet preview and assign it to $this->content.
*/
protected function set_content() {
$content = <<<HTML
/**
* Generates the html for the snippet preview and assign it to $this->content.
*/
protected function set_content() {
$content = <<<HTML
<div id="wpseosnippet">
<a class="title" id="wpseosnippet_title" href="#">$this->title</a>
<span class="url">$this->url</span>
<p class="desc">$this->date<span class="autogen"></span><span class="content">$this->description</span></p>
</div>
HTML;
$this->set_content_through_filter( $content );
}
$this->set_content_through_filter( $content );
}
/**
* Sets the html for the snippet preview through a filter
*
* @param string $content
*/
protected function set_content_through_filter( $content ) {
$properties = get_object_vars( $this );
// Backward compatibility for functions hooking into the wpseo_snippet filter
$properties['desc'] = $properties['description'];
/**
* Sets the html for the snippet preview through a filter
* Filter: 'wpseo_snippet' - Allow changing the html for the snippet preview.
*
* Passing in the post twice because of backwards compatibility.
*/
protected function set_content_through_filter( $content ) {
$properties = get_object_vars( $this );
/**
* Filter: 'wpseo_snippet' - Allow changing the html for the snippet preview.
*
* Passing in the post twice because of backwards compatibility.
*/
$this->content = apply_filters( 'wpseo_snippet', $content, $this->post, $properties );
}
$this->content = apply_filters( 'wpseo_snippet', $content, $this->post, $properties );
}
}
@@ -0,0 +1,346 @@
<?php
/**
* @package WPSEO
* @subpackage Admin
*/
/**
* The Facebook insights class, this will add some listeners to fetch GET params
*/
class Yoast_Social_Facebook {
/**
* @var array - The options for social
*/
private $options;
/**
* Setting the options and define the listener to fetch $_GET values
*
*/
public function __construct() {
$this->options = get_option( 'wpseo_social' );
$this->get_listener();
}
/**
* Returns the output from the form class
*
*/
public function show_form() {
$form = new Yoast_Social_Facebook_Form();
$form->show_form();
}
/**
* This method will hook into the defined get params
*
*/
private function get_listener() {
if ( $delfbadmin = filter_input( INPUT_GET, 'delfbadmin' ) ) {
$this->delete_admin( $delfbadmin );
}
elseif ( filter_input( INPUT_GET, 'fbclearall' ) ) {
$this->clear_all();
}
elseif ( $key = filter_input( INPUT_GET, 'key' ) ) {
$this->handle_user( $key );
}
}
/**
* Deletes the admin from the options
*
* @param string $delfbadmin
*/
private function delete_admin( $delfbadmin ) {
$this->verify_nonce( 'delfbadmin' );
$admin_id = sanitize_text_field( $delfbadmin );
if ( isset( $this->options['fb_admins'][ $admin_id ] ) ) {
$fbadmin = $this->options['fb_admins'][ $admin_id ]['name'];
unset( $this->options['fb_admins'][ $admin_id ] );
$this->save_options();
$this->success_notice( sprintf( __( 'Successfully removed admin %s', 'wordpress-seo' ), $fbadmin ) );
unset( $fbadmin );
}
unset( $admin_id );
// Clean up the referrer url for later use
if ( filter_input( INPUT_SERVER, 'REQUEST_URI' ) ) {
$this->cleanup_referrer_url( 'nonce', 'delfbadmin' );
}
}
/**
* Clear all the facebook that has been set already
*
*/
private function clear_all() {
$this->verify_nonce( 'fbclearall' );
// Reset to defaults, don't unset as otherwise the old values will be retained
$this->options['fb_admins'] = WPSEO_Options::get_default( 'wpseo_social', 'fb_admins' );
$this->save_options();
$this->success_notice( __( 'Successfully cleared all Facebook Data', 'wordpress-seo' ) );
// Clean up the referrer url for later use
if ( filter_input( INPUT_SERVER, 'REQUEST_URI' ) ) {
$this->cleanup_referrer_url( 'nonce', 'fbclearall' );
}
}
/**
* Adding a new facebook admin
*
* @param string $key_value
*/
private function handle_user( $key_value ) {
if ( $key_value === $this->options['fbconnectkey'] && $user_id = filter_input( INPUT_GET, 'userid', FILTER_CALLBACK, array( 'options' => 'sanitize_text_field' ) ) ) {
if ( ! isset( $this->options['fb_admins'][ $user_id ] ) ) {
$this->options['fb_admins'][ $user_id ]['name'] = sanitize_text_field( urldecode( filter_input( INPUT_GET, 'userrealname' ) ) );
$this->options['fb_admins'][ $user_id ]['link'] = sanitize_text_field( urldecode( filter_input( INPUT_GET, 'link' ) ) );
$this->save_options();
$this->success_notice(
sprintf( __( 'Successfully added %s as a Facebook Admin!', 'wordpress-seo' ), '<a href="' . esc_url( $this->options['fb_admins'][ $user_id ]['link'] ) . '">' . esc_html( $this->options['fb_admins'][ $user_id ]['name'] ) . '</a>' )
);
}
else {
add_settings_error(
'yoast_wpseo_social_options',
'error',
sprintf(
__( '%s already exists as a Facebook Admin.', 'wordpress-seo' ),
'<a href="' . esc_url( $this->options['fb_admins'][ $user_id ]['link'] ) . '">' . esc_html( $this->options['fb_admins'][ $user_id ]['name'] ) . '</a>'
),
'error'
);
}
unset( $user_id );
}
// Clean up the referrer url for later use
if ( filter_input( INPUT_SERVER, 'REQUEST_URI' ) ) {
$this->cleanup_referrer_url( 'key', 'userid', 'userrealname', 'link' );
}
}
/**
* Clean up the request_uri. The given params are the params that will be removed from the URL
*/
private function cleanup_referrer_url() {
$_SERVER['REQUEST_URI'] = remove_query_arg(
func_get_args(),
filter_input(
INPUT_SERVER, 'REQUEST_URI', FILTER_CALLBACK, array( 'options' => 'sanitize_text_field' )
)
);
}
/**
* When something is going well, show a success notice
*
* @param string $notice_text
*/
private function success_notice( $notice_text ) {
add_settings_error( 'yoast_wpseo_social_options', 'success', $notice_text, 'updated' );
}
/**
* Verify the nonce from the URL with the saved nonce
*
* @param string $nonce_name
*/
private function verify_nonce( $nonce_name ) {
if ( wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), $nonce_name ) != 1 ) {
die( "I don't think that's really nice of you!." );
}
}
/**
* Saving the options
*/
private function save_options() {
update_option( 'wpseo_social', $this->options );
}
}
/**
* This will display the HTML for the facebook insights part
*/
class Yoast_Social_Facebook_Form {
/**
* @var array - The options for social
*/
private $options;
/**
* @var array - The repository for the buttons that will be shown
*/
private $buttons = array();
/**
* @var string - The URL to link to
*/
private $admin_url = 'admin.php?page=wpseo_social';
/**
* Setting the options and call the methods to display everything
*
*/
public function __construct() {
$this->options = get_option( 'wpseo_social' );
}
/**
* Returns the output-property
*/
public function show_form() {
$this
->form_head()
->manage_user_admin()
->show_buttons()
->manage_app_as_admin();
}
/**
* SHow the top of the social insights part of the page
*
* @return $this
*/
private function form_head() {
echo '<p><strong>' . esc_html__( 'Facebook Insights and Admins', 'wordpress-seo' ) . '</strong><br />';
echo sprintf(
esc_html__(
'To be able to access %sFacebook Insights%s for your site, you need to specify a Facebook Admin. This can be a user. If you have an app for your site, you could use that as well.', 'wordpress-seo'
),
'<a href="https://www.facebook.com/insights">',
'</a>'
);
echo'</p>';
return $this;
}
/**
* Display the buttons to add an admin or add another admin from Facebook and display the admin that has been added already.
*
* @return $this
*/
private function manage_user_admin() {
$button_text = __( 'Add Facebook Admin', 'wordpress-seo' );
if ( is_array( $this->options['fb_admins'] ) && $this->options['fb_admins'] !== array() ) {
$nonce = wp_create_nonce( 'delfbadmin' );
$button_text = __( 'Add Another Facebook Admin', 'wordpress-seo' );
echo '<p>' . __( 'Currently connected Facebook admins:', 'wordpress-seo' ) . '</p>';
echo '<ul>';
$this->show_user_admins( $nonce );
echo '</ul>';
unset( $admin_id, $admin, $nonce );
}
$this->add_button(
'https://yoast.com/fb-connect/?key=' . urlencode( $this->options['fbconnectkey'] ) . '&redirect=' . urlencode( admin_url( $this->admin_url ) ),
$button_text,'',
true
);
return $this;
}
/**
* Show input field to set a facebook apps as an admin
*
* @return $this
*/
private function manage_app_as_admin() {
echo '<div class="clear"></div><br />';
Yoast_Form::get_instance()->textinput( 'fbadminapp', __( 'Facebook App ID', 'wordpress-seo' ) );
return $this;
}
/**
* Loop through the fb-admins to parse the output for them
*
* @param string $nonce
*/
private function show_user_admins( $nonce ) {
foreach ( $this->options['fb_admins'] as $admin_id => $admin ) {
echo '<li><a href="' . esc_url( $admin['link'] ) . '">' . esc_html( $admin['name'] ) . '</a>';
echo ' - <strong><a href="' . $this->admin_delete_link( $admin_id, $nonce ) . '">X</a></strong></li>';
}
}
/**
* Parsing the link that directs to the admin removal
*
* @param string $admin_id
* @param string $nonce
*
* @return string
*/
private function admin_delete_link( $admin_id, $nonce ) {
return esc_url(
add_query_arg(
array(
'delfbadmin' => esc_attr( $admin_id ),
'nonce' => $nonce,
),
admin_url( $this->admin_url . '#top#facebook' )
)
);
}
/**
* Adding a button to the button property
*
* @param string $button_url
* @param string $button_value
* @param string $button_class
* @param string $button_id
*/
private function add_button( $button_url, $button_value, $button_class = '', $button_id = '' ) {
$this->buttons[] = '<a id="' .esc_attr( $button_id ). '" class="button' . esc_attr( $button_class ) . '" href="' . esc_url( $button_url ) . '">' . esc_html( $button_value ) . '</a>';
}
/**
* Showing the buttons
*/
private function show_buttons() {
if ( $this->get_clearall() ) {
$this->add_button(
esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'fbclearall' ), 'fbclearall' => 'true', ), admin_url( $this->admin_url . '#top#facebook' ) ) ),
__( 'Clear all Facebook Data', 'wordpress-seo' )
);
}
if ( is_array( $this->buttons ) && $this->buttons !== array() ) {
echo '<p class="fb-buttons">' . implode( '', $this->buttons ) . '</p>';
}
return $this;
}
/**
* Check if the clear button should be displayed. This is based on the the set options
*
* @return bool
*/
private function get_clearall() {
return is_array( $this->options['fb_admins'] ) && $this->options['fb_admins'] !== array();
}
}
@@ -1,285 +1,296 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Class that handles the edit boxes on taxonomy edit pages.
*/
class WPSEO_Taxonomy {
if ( ! class_exists( 'WPSEO_Taxonomy' ) ) {
/**
* Class that handles the edit boxes on taxonomy edit pages.
* @var array Options array for the no-index options, including translated labels
*/
class WPSEO_Taxonomy {
public $no_index_options = array();
/**
* @var array Options array for the no-index options, including translated labels
*/
public $no_index_options = array();
/**
* @var array Options array for the sitemap_include options, including translated labels
*/
public $sitemap_include_options = array();
/**
* @var array Options array for the sitemap_include options, including translated labels
*/
public $sitemap_include_options = array();
/**
* Class constructor
*/
function __construct() {
$options = WPSEO_Options::get_all();
/**
* Class constructor
*/
function __construct() {
$options = WPSEO_Options::get_all();
if ( is_admin() && ( isset( $_GET['taxonomy'] ) && $_GET['taxonomy'] !== '' ) &&
( ! isset( $options[ 'hideeditbox-tax-' . $_GET['taxonomy'] ] ) || $options[ 'hideeditbox-tax-' . $_GET['taxonomy'] ] === false )
) {
add_action( sanitize_text_field( $_GET['taxonomy'] ) . '_edit_form', array( $this, 'term_seo_form' ), 90, 1 );
}
add_action( 'edit_term', array( $this, 'update_term' ), 99, 3 );
add_action( 'init', array( $this, 'custom_category_descriptions_allow_html' ) );
add_filter( 'category_description', array( $this, 'custom_category_descriptions_add_shortcode_support' ) );
add_action( 'admin_init', array( $this, 'translate_meta_options' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
if ( is_admin() && ( isset( $_GET['taxonomy'] ) && $_GET['taxonomy'] !== '' ) &&
( ! isset( $options[ 'hideeditbox-tax-' . $_GET['taxonomy'] ] ) || $options[ 'hideeditbox-tax-' . $_GET['taxonomy'] ] === false )
) {
add_action( sanitize_text_field( $_GET['taxonomy'] ) . '_edit_form', array(
$this,
'term_seo_form',
), 90, 1 );
}
add_action( 'split_shared_term', array( $this, 'split_shared_term' ), 10, 4 );
add_action( 'edit_term', array( $this, 'update_term' ), 99, 3 );
/**
* Translate options text strings for use in the select fields
*
* @internal IMPORTANT: if you want to add a new string (option) somewhere, make sure you add
* that array key to the main options definition array in the class WPSEO_Taxonomy_Meta() as well!!!!
*/
public function translate_meta_options() {
$this->no_index_options = WPSEO_Taxonomy_Meta::$no_index_options;
$this->sitemap_include_options = WPSEO_Taxonomy_Meta::$sitemap_include_options;
add_action( 'init', array( $this, 'custom_category_descriptions_allow_html' ) );
add_filter( 'category_description', array( $this, 'custom_category_descriptions_add_shortcode_support' ) );
add_action( 'admin_init', array( $this, 'translate_meta_options' ) );
$this->no_index_options['default'] = __( 'Use %s default (Currently: %s)', 'wordpress-seo' );
$this->no_index_options['index'] = __( 'Always index', 'wordpress-seo' );
$this->no_index_options['noindex'] = __( 'Always noindex', 'wordpress-seo' );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
}
$this->sitemap_include_options['-'] = __( 'Auto detect', 'wordpress-seo' );
$this->sitemap_include_options['always'] = __( 'Always include', 'wordpress-seo' );
$this->sitemap_include_options['never'] = __( 'Never include', 'wordpress-seo' );
}
/**
* Test whether we are on a public taxonomy - no metabox actions needed if we are not
* Unfortunately we have to hook most everything in before the point where all taxonomies are registered and
* we know which taxonomy is being requested, so we need to use this check in nearly every hooked in function.
*
* @since 1.5.0
*/
function tax_is_public() {
// Don't make static as taxonomies may still be added during the run
$taxonomies = get_taxonomies( array( 'public' => true ), 'names' );
return ( isset( $_GET['taxonomy'] ) && in_array( $_GET['taxonomy'], $taxonomies ) );
}
/**
* Add our admin css file
*/
function admin_enqueue_scripts() {
global $pagenow;
if ( $pagenow === 'edit-tags.php' && ( isset( $_GET['action'] ) && $_GET['action'] === 'edit' ) ) {
wp_enqueue_style( 'yoast-taxonomy-css', plugins_url( 'css/taxonomy-meta' . WPSEO_CSSJS_SUFFIX . '.css', WPSEO_FILE ), array(), WPSEO_VERSION );
}
}
/**
* Create a row in the form table.
*
* @param string $var Variable the row controls.
* @param string $label Label for the variable.
* @param string $desc Description of the use of the variable.
* @param array $tax_meta Taxonomy meta value.
* @param string $type Type of form row to create.
* @param array $options Options to use when form row is a select box.
*/
function form_row( $var, $label, $desc, $tax_meta, $type = 'text', $options = array() ) {
$val = '';
if ( isset( $tax_meta[ $var ] ) && $tax_meta[ $var ] !== '' ) {
$val = $tax_meta[ $var ];
}
$esc_var = esc_attr( $var );
$field = '';
if ( $type == 'text' ) {
$field .= '
<input name="' . $esc_var . '" id="' . $esc_var . '" type="text" value="' . esc_attr( $val ) . '" size="40"/>';
}
elseif ( $type == 'checkbox' ) {
$field .= '
<input name="' . $esc_var . '" id="' . $esc_var . '" type="checkbox" ' . checked( $val ) . '/>';
}
elseif ( $type == 'select' ) {
if ( is_array( $options ) && $options !== array() ) {
$field .= '
<select name="' . $esc_var . '" id="' . $esc_var . '">';
foreach ( $options as $option => $option_label ) {
$selected = selected( $option, $val, false );
$field .= '
<option ' . $selected . ' value="' . esc_attr( $option ) . '">' . esc_html( $option_label ) . '</option>';
}
$field .= '
</select>';
}
}
elseif ( $type == 'hidden' ) {
$field .= '
<input name="' . $esc_var . '" id="hidden_' . $esc_var . '" type="hidden" value="' . esc_attr( $val ) . '" />';
}
if ( $field !== '' && ( is_string( $desc ) && $desc !== '' ) ) {
$field .= '
<p class="description">' . $desc . '</p>';
}
echo '
<tr class="form-field">
<th scope="row">' . ( '' !== $label ? '<label for="' . $esc_var . '">' . esc_html( $label ) . ':</label>' : '' ) . '</th>
<td>' . $field . '</td>
</tr>';
}
/**
* Show the SEO inputs for term.
*
* @param object $term Term to show the edit boxes for.
*/
function term_seo_form( $term ) {
if ( $this->tax_is_public() === false ) {
return;
}
$tax_meta = WPSEO_Taxonomy_Meta::get_term_meta( (int) $term->term_id, $term->taxonomy );
$options = WPSEO_Options::get_all();
echo '<h2>' . __( 'Yoast WordPress SEO Settings', 'wordpress-seo' ) . '</h2>';
echo '<table class="form-table wpseo-taxonomy-form">';
$this->form_row( 'wpseo_title', __( 'SEO Title', 'wordpress-seo' ), esc_html__( 'The SEO title is used on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
$this->form_row( 'wpseo_desc', __( 'SEO Description', 'wordpress-seo' ), esc_html__( 'The SEO description is used for the meta description on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
if ( $options['usemetakeywords'] === true ) {
$this->form_row( 'wpseo_metakey', __( 'Meta keywords', 'wordpress-seo' ), esc_html__( 'Meta keywords used on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
}
$this->form_row( 'wpseo_canonical', __( 'Canonical', 'wordpress-seo' ), esc_html__( 'The canonical link is shown on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
if ( $options['breadcrumbs-enable'] === true ) {
$this->form_row( 'wpseo_bctitle', __( 'Breadcrumbs title', 'wordpress-seo' ), sprintf( esc_html__( 'The Breadcrumbs title is used in the breadcrumbs where this %s appears.', 'wordpress-seo' ), $term->taxonomy ), $tax_meta );
}
$current = 'index';
if ( isset( $options[ 'noindex-tax-' . $term->taxonomy ] ) && $options[ 'noindex-tax-' . $term->taxonomy ] === true ) {
$current = 'noindex';
}
$noindex_options = $this->no_index_options;
$noindex_options['default'] = sprintf( $noindex_options['default'], $term->taxonomy, $current );
$desc = sprintf( esc_html__( 'This %s follows the indexation rules set under Metas and Titles, you can override it here.', 'wordpress-seo' ), $term->taxonomy );
if ( '0' == get_option( 'blog_public' ) ) {
$desc .= '<br /><span class="error-message">' . esc_html__( 'Warning: even though you can set the meta robots setting here, the entire site is set to noindex in the sitewide privacy settings, so these settings won\'t have an effect.', 'wordpress-seo' ) . '</span>';
}
$this->form_row( 'wpseo_noindex', sprintf( __( 'Noindex this %s', 'wordpress-seo' ), $term->taxonomy ), $desc, $tax_meta, 'select', $noindex_options );
unset( $current, $no_index_options, $desc );
$this->form_row( 'wpseo_sitemap_include', __( 'Include in sitemap?', 'wordpress-seo' ), '', $tax_meta, 'select', $this->sitemap_include_options );
echo '</table>';
}
/**
* Update the taxonomy meta data on save.
*
* @param int $term_id ID of the term to save data for
* @param int $tt_id The taxonomy_term_id for the term.
* @param string $taxonomy The taxonomy the term belongs to.
*/
function update_term( $term_id, $tt_id, $taxonomy ) {
$tax_meta = get_option( 'wpseo_taxonomy_meta' );
/* Create post array with only our values */
$new_meta_data = array();
foreach ( WPSEO_Taxonomy_Meta::$defaults_per_term as $key => $default ) {
if ( isset( $_POST[ $key ] ) ) {
$new_meta_data[ $key ] = $_POST[ $key ];
}
}
/* Validate the post values */
$old = WPSEO_Taxonomy_Meta::get_term_meta( $term_id, $taxonomy );
$clean = WPSEO_Taxonomy_Meta::validate_term_meta_data( $new_meta_data, $old );
/* Add/remove the result to/from the original option value */
if ( $clean !== array() ) {
$tax_meta[ $taxonomy ][ $term_id ] = $clean;
}
else {
unset( $tax_meta[ $taxonomy ][ $term_id ] );
if ( isset( $tax_meta[ $taxonomy ] ) && $tax_meta[ $taxonomy ] === array() ) {
unset( $tax_meta[ $taxonomy ] );
}
}
// Prevent complete array validation
$tax_meta['wpseo_already_validated'] = true;
/**
* Makes sure the taxonomy meta is updated when a taxonomy term is split.
*
* @link https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/ Article explaining the taxonomy term splitting in WP 4.2
*
* @param string $old_term_id Old term id of the taxonomy term that was splitted.
* @param string $new_term_id New term id of the taxonomy term that was splitted.
* @param string $term_taxonomy_id Term taxonomy id for the taxonomy that was affected.
* @param string $taxonomy The taxonomy that the taxonomy term was splitted for.
*/
public function split_shared_term( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
$tax_meta = get_option( 'wpseo_taxonomy_meta', array() );
if ( ! empty( $tax_meta[ $taxonomy ][ $old_term_id ] ) ) {
$tax_meta[ $taxonomy ][ $new_term_id ] = $tax_meta[ $taxonomy ][ $old_term_id ];
unset( $tax_meta[ $taxonomy ][ $old_term_id ]);
update_option( 'wpseo_taxonomy_meta', $tax_meta );
}
}
/**
* Translate options text strings for use in the select fields
*
* @internal IMPORTANT: if you want to add a new string (option) somewhere, make sure you add
* that array key to the main options definition array in the class WPSEO_Taxonomy_Meta() as well!!!!
*/
public function translate_meta_options() {
$this->no_index_options = WPSEO_Taxonomy_Meta::$no_index_options;
$this->sitemap_include_options = WPSEO_Taxonomy_Meta::$sitemap_include_options;
$this->no_index_options['default'] = __( 'Use %s default (Currently: %s)', 'wordpress-seo' );
$this->no_index_options['index'] = __( 'Always index', 'wordpress-seo' );
$this->no_index_options['noindex'] = __( 'Always noindex', 'wordpress-seo' );
$this->sitemap_include_options['-'] = __( 'Auto detect', 'wordpress-seo' );
$this->sitemap_include_options['always'] = __( 'Always include', 'wordpress-seo' );
$this->sitemap_include_options['never'] = __( 'Never include', 'wordpress-seo' );
}
/**
* Allows HTML in descriptions
*/
function custom_category_descriptions_allow_html() {
$filters = array(
'pre_term_description',
'pre_link_description',
'pre_link_notes',
'pre_user_description',
);
/**
* Test whether we are on a public taxonomy - no metabox actions needed if we are not
* Unfortunately we have to hook most everything in before the point where all taxonomies are registered and
* we know which taxonomy is being requested, so we need to use this check in nearly every hooked in function.
*
* @since 1.5.0
*/
function tax_is_public() {
// Don't make static as taxonomies may still be added during the run
$taxonomies = get_taxonomies( array( 'public' => true ), 'names' );
foreach ( $filters as $filter ) {
remove_filter( $filter, 'wp_filter_kses' );
return ( isset( $_GET['taxonomy'] ) && in_array( $_GET['taxonomy'], $taxonomies ) );
}
/**
* Add our admin css file
*/
function admin_enqueue_scripts() {
if ( $GLOBALS['pagenow'] === 'edit-tags.php' && ( isset( $_GET['action'] ) && $_GET['action'] === 'edit' ) ) {
wp_enqueue_style( 'yoast-taxonomy-css', plugins_url( 'css/taxonomy-meta' . WPSEO_CSSJS_SUFFIX . '.css', WPSEO_FILE ), array(), WPSEO_VERSION );
}
}
/**
* Create a row in the form table.
*
* @param string $var Variable the row controls.
* @param string $label Label for the variable.
* @param string $desc Description of the use of the variable.
* @param array $tax_meta Taxonomy meta value.
* @param string $type Type of form row to create.
* @param array $options Options to use when form row is a select box.
*/
function form_row( $var, $label, $desc, $tax_meta, $type = 'text', $options = array() ) {
$val = '';
if ( isset( $tax_meta[ $var ] ) && $tax_meta[ $var ] !== '' ) {
$val = $tax_meta[ $var ];
}
$esc_var = esc_attr( $var );
$field = '';
if ( $type == 'text' ) {
$field .= '
<input name="' . $esc_var . '" id="' . $esc_var . '" type="text" value="' . esc_attr( $val ) . '" size="40"/>';
}
elseif ( $type == 'checkbox' ) {
$field .= '
<input name="' . $esc_var . '" id="' . $esc_var . '" type="checkbox" ' . checked( $val ) . '/>';
}
elseif ( $type == 'select' ) {
if ( is_array( $options ) && $options !== array() ) {
$field .= '
<select name="' . $esc_var . '" id="' . $esc_var . '">';
foreach ( $options as $option => $option_label ) {
$selected = selected( $option, $val, false );
$field .= '
<option ' . $selected . ' value="' . esc_attr( $option ) . '">' . esc_html( $option_label ) . '</option>';
}
unset( $option, $option_label, $selected );
$field .= '
</select>';
}
remove_filter( 'term_description', 'wp_kses_data' );
}
elseif ( $type == 'hidden' ) {
$field .= '
<input name="' . $esc_var . '" id="hidden_' . $esc_var . '" type="hidden" value="' . esc_attr( $val ) . '" />';
}
/**
* Adds shortcode support to category descriptions.
*
* @param string $desc String to add shortcodes in.
* @return string
*/
function custom_category_descriptions_add_shortcode_support( $desc ) {
// Wrap in output buffering to prevent shortcodes that echo stuff instead of return from breaking things.
ob_start();
$desc = do_shortcode( $desc );
ob_end_clean();
return $desc;
if ( $field !== '' && ( is_string( $desc ) && $desc !== '' ) ) {
$field .= '
<p class="description">' . $desc . '</p>';
}
} /* End of class */
} /* End of class-exists wrapper */
echo '
<tr class="form-field">
<th scope="row">' . ( ( '' !== $label ) ? '<label for="' . $esc_var . '">' . esc_html( $label ) . ':</label>' : '' ) . '</th>
<td>' . $field . '</td>
</tr>';
}
/**
* Show the SEO inputs for term.
*
* @param object $term Term to show the edit boxes for.
*/
function term_seo_form( $term ) {
if ( $this->tax_is_public() === false ) {
return;
}
$tax_meta = WPSEO_Taxonomy_Meta::get_term_meta( (int) $term->term_id, $term->taxonomy );
$options = WPSEO_Options::get_all();
echo '<h2>', __( 'Yoast WordPress SEO Settings', 'wordpress-seo' ), '</h2>';
echo '<table class="form-table wpseo-taxonomy-form">';
$this->form_row( 'wpseo_title', __( 'SEO Title', 'wordpress-seo' ), esc_html__( 'The SEO title is used on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
$this->form_row( 'wpseo_desc', __( 'SEO Description', 'wordpress-seo' ), esc_html__( 'The SEO description is used for the meta description on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
if ( $options['usemetakeywords'] === true ) {
$this->form_row( 'wpseo_metakey', __( 'Meta keywords', 'wordpress-seo' ), esc_html__( 'Meta keywords used on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
}
$this->form_row( 'wpseo_canonical', __( 'Canonical', 'wordpress-seo' ), esc_html__( 'The canonical link is shown on the archive page for this term.', 'wordpress-seo' ), $tax_meta );
if ( $options['breadcrumbs-enable'] === true ) {
$this->form_row( 'wpseo_bctitle', __( 'Breadcrumbs title', 'wordpress-seo' ), sprintf( esc_html__( 'The Breadcrumbs title is used in the breadcrumbs where this %s appears.', 'wordpress-seo' ), $term->taxonomy ), $tax_meta );
}
$current = 'index';
if ( isset( $options[ 'noindex-tax-' . $term->taxonomy ] ) && $options[ 'noindex-tax-' . $term->taxonomy ] === true ) {
$current = 'noindex';
}
$noindex_options = $this->no_index_options;
$noindex_options['default'] = sprintf( $noindex_options['default'], $term->taxonomy, $current );
$desc = sprintf( esc_html__( 'This %s follows the indexation rules set under Metas and Titles, you can override it here.', 'wordpress-seo' ), $term->taxonomy );
if ( '0' == get_option( 'blog_public' ) ) {
$desc .= '<br /><span class="error-message">' . esc_html__( 'Warning: even though you can set the meta robots setting here, the entire site is set to noindex in the sitewide privacy settings, so these settings won\'t have an effect.', 'wordpress-seo' ) . '</span>';
}
$this->form_row( 'wpseo_noindex', sprintf( __( 'Noindex this %s', 'wordpress-seo' ), $term->taxonomy ), $desc, $tax_meta, 'select', $noindex_options );
unset( $current, $no_index_options, $desc );
$this->form_row( 'wpseo_sitemap_include', __( 'Include in sitemap?', 'wordpress-seo' ), '', $tax_meta, 'select', $this->sitemap_include_options );
echo '</table>';
}
/**
* Update the taxonomy meta data on save.
*
* @param int $term_id ID of the term to save data for
* @param int $tt_id The taxonomy_term_id for the term.
* @param string $taxonomy The taxonomy the term belongs to.
*/
function update_term( $term_id, $tt_id, $taxonomy ) {
$tax_meta = get_option( 'wpseo_taxonomy_meta' );
/* Create post array with only our values */
$new_meta_data = array();
foreach ( WPSEO_Taxonomy_Meta::$defaults_per_term as $key => $default ) {
if ( isset( $_POST[ $key ] ) ) {
$new_meta_data[ $key ] = $_POST[ $key ];
}
}
unset( $key, $default );
/* Validate the post values */
$old = WPSEO_Taxonomy_Meta::get_term_meta( $term_id, $taxonomy );
$clean = WPSEO_Taxonomy_Meta::validate_term_meta_data( $new_meta_data, $old );
/* Add/remove the result to/from the original option value */
if ( $clean !== array() ) {
$tax_meta[ $taxonomy ][ $term_id ] = $clean;
}
else {
unset( $tax_meta[ $taxonomy ][ $term_id ] );
if ( isset( $tax_meta[ $taxonomy ] ) && $tax_meta[ $taxonomy ] === array() ) {
unset( $tax_meta[ $taxonomy ] );
}
}
// Prevent complete array validation
$tax_meta['wpseo_already_validated'] = true;
update_option( 'wpseo_taxonomy_meta', $tax_meta );
}
/**
* Allows HTML in descriptions
*/
function custom_category_descriptions_allow_html() {
$filters = array(
'pre_term_description',
'pre_link_description',
'pre_link_notes',
'pre_user_description',
);
foreach ( $filters as $filter ) {
remove_filter( $filter, 'wp_filter_kses' );
}
remove_filter( 'term_description', 'wp_kses_data' );
}
/**
* Adds shortcode support to category descriptions.
*
* @param string $desc String to add shortcodes in.
*
* @return string
*/
function custom_category_descriptions_add_shortcode_support( $desc ) {
// Wrap in output buffering to prevent shortcodes that echo stuff instead of return from breaking things.
ob_start();
$desc = do_shortcode( $desc );
ob_end_clean();
return $desc;
}
} /* End of class */
@@ -1,6 +1,10 @@
<?php
/**
* @package Admin
* Contains the Tracking class and filtering specific to WordPress SEO for the tracking class.
*
* If the class is instatiated from another plugin, the filtering still works.
*
* @package WPSEO\Admin\Tracking
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,165 +13,164 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
if ( ! class_exists( 'Yoast_Tracking' ) ) {
/**
* Class that creates the tracking functionality for WP SEO, as the core class might be used in more plugins,
* it's checked for existence first.
*
* NOTE: this functionality is opt-in. Disabling the tracking in the settings or saying no when asked will cause
* this file to not even be loaded.
*
* @todo [JRF => testers] check if tracking still works if an old version of the Yoast Tracking class was loaded
* (i.e. another plugin loaded their version first)
*/
class Yoast_Tracking {
/**
* Class that creates the tracking functionality for WP SEO, as the core class might be used in more plugins,
* it's checked for existence first.
*
* NOTE: this functionality is opt-in. Disabling the tracking in the settings or saying no when asked will cause
* this file to not even be loaded.
*
* @todo [JRF => testers] check if tracking still works if an old version of the Yoast Tracking class was loaded
* (i.e. another plugin loaded their version first)
* @var object Instance of this class
*/
class Yoast_Tracking {
/**
* @var object Instance of this class
*/
public static $instance;
public static $instance;
/**
* Class constructor
*/
function __construct() {
// Constructor is called from WP SEO
if ( current_filter( 'yoast_tracking' ) ) {
$this->tracking();
} // Backward compatibility - constructor is called from other Yoast plugin
elseif ( ! has_action( 'yoast_tracking', array( $this, 'tracking' ) ) ) {
add_action( 'yoast_tracking', array( $this, 'tracking' ) );
}
/**
* Class constructor
*/
function __construct() {
// Constructor is called from WP SEO
if ( current_filter( 'yoast_tracking' ) ) {
$this->tracking();
} // Backward compatibility - constructor is called from other Yoast plugin
elseif ( ! has_action( 'yoast_tracking', array( $this, 'tracking' ) ) ) {
add_action( 'yoast_tracking', array( $this, 'tracking' ) );
}
}
/**
* Get the singleton instance of this class
*
* @return object
*/
public static function get_instance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
/**
* Get the singleton instance of this class
*
* @return object
*/
public static function get_instance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
return self::$instance;
}
return self::$instance;
/**
* Main tracking function.
*/
function tracking() {
$transient_key = 'yoast_tracking_cache';
$data = get_transient( $transient_key );
// bail if transient is set and valid
if ( $data !== false ) {
return;
}
/**
* Main tracking function.
*/
function tracking() {
// Make sure to only send tracking data once a week
set_transient( $transient_key, 1, WEEK_IN_SECONDS );
$transient_key = 'yoast_tracking_cache';
$data = get_transient( $transient_key );
// Start of Metrics
global $wpdb;
// bail if transient is set and valid
if ( $data !== false ) {
return;
}
// Make sure to only send tracking data once a week
set_transient( $transient_key, 1, WEEK_IN_SECONDS );
// Start of Metrics
global $blog_id, $wpdb;
$hash = get_option( 'Yoast_Tracking_Hash', false );
if ( ! $hash || empty( $hash ) ) {
// create and store hash
$hash = md5( site_url() );
update_option( 'Yoast_Tracking_Hash', $hash );
}
$pts = array();
$post_types = get_post_types( array( 'public' => true ) );
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $post_type ) {
$count = wp_count_posts( $post_type );
$pts[ $post_type ] = $count->publish;
}
}
unset( $post_types );
$comments_count = wp_count_comments();
$theme_data = wp_get_theme();
$theme = array(
'name' => $theme_data->display( 'Name', false, false ),
'theme_uri' => $theme_data->display( 'ThemeURI', false, false ),
'version' => $theme_data->display( 'Version', false, false ),
'author' => $theme_data->display( 'Author', false, false ),
'author_uri' => $theme_data->display( 'AuthorURI', false, false ),
);
$theme_template = $theme_data->get_template();
if ( $theme_template !== '' && $theme_data->parent() ) {
$theme['template'] = array(
'version' => $theme_data->parent()->display( 'Version', false, false ),
'name' => $theme_data->parent()->display( 'Name', false, false ),
'theme_uri' => $theme_data->parent()->display( 'ThemeURI', false, false ),
'author' => $theme_data->parent()->display( 'Author', false, false ),
'author_uri' => $theme_data->parent()->display( 'AuthorURI', false, false ),
);
} else {
$theme['template'] = '';
}
unset( $theme_template );
$plugins = array();
$active_plugin = get_option( 'active_plugins' );
foreach ( $active_plugin as $plugin_path ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_path );
$slug = str_replace( '/' . basename( $plugin_path ), '', $plugin_path );
$plugins[ $slug ] = array(
'version' => $plugin_info['Version'],
'name' => $plugin_info['Name'],
'plugin_uri' => $plugin_info['PluginURI'],
'author' => $plugin_info['AuthorName'],
'author_uri' => $plugin_info['AuthorURI'],
);
}
unset( $active_plugins, $plugin_path );
$data = array(
'site' => array(
'hash' => $hash,
'version' => get_bloginfo( 'version' ),
'multisite' => is_multisite(),
'users' => $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->users INNER JOIN $wpdb->usermeta ON ({$wpdb->users}.ID = {$wpdb->usermeta}.user_id) WHERE 1 = 1 AND ( {$wpdb->usermeta}.meta_key = %s )", 'wp_' . $blog_id . '_capabilities' ) ),
'lang' => get_locale(),
),
'pts' => $pts,
'comments' => array(
'total' => $comments_count->total_comments,
'approved' => $comments_count->approved,
'spam' => $comments_count->spam,
'pings' => $wpdb->get_var( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_type = 'pingback'" ),
),
'options' => apply_filters( 'yoast_tracking_filters', array() ),
'theme' => $theme,
'plugins' => $plugins,
);
$args = array(
'body' => $data,
'blocking' => false,
'sslverify' => false,
);
wp_remote_post( 'https://tracking.yoast.com/', $args );
$hash = get_option( 'Yoast_Tracking_Hash', false );
if ( ! $hash || empty( $hash ) ) {
// create and store hash
$hash = md5( site_url() );
update_option( 'Yoast_Tracking_Hash', $hash );
}
} /* End of class */
} /* End of class-exists wrapper */
$pts = array();
$post_types = get_post_types( array( 'public' => true ) );
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $post_type ) {
$count = wp_count_posts( $post_type );
$pts[ $post_type ] = $count->publish;
}
}
unset( $post_types, $post_type, $count );
$comments_count = wp_count_comments();
$theme_data = wp_get_theme();
$theme = array(
'name' => $theme_data->display( 'Name', false, false ),
'theme_uri' => $theme_data->display( 'ThemeURI', false, false ),
'version' => $theme_data->display( 'Version', false, false ),
'author' => $theme_data->display( 'Author', false, false ),
'author_uri' => $theme_data->display( 'AuthorURI', false, false ),
);
$theme_template = $theme_data->get_template();
if ( $theme_template !== '' && $theme_data->parent() ) {
$theme['template'] = array(
'version' => $theme_data->parent()->display( 'Version', false, false ),
'name' => $theme_data->parent()->display( 'Name', false, false ),
'theme_uri' => $theme_data->parent()->display( 'ThemeURI', false, false ),
'author' => $theme_data->parent()->display( 'Author', false, false ),
'author_uri' => $theme_data->parent()->display( 'AuthorURI', false, false ),
);
}
else {
$theme['template'] = '';
}
unset( $theme_template );
$plugins = array();
$active_plugins = get_option( 'active_plugins' );
foreach ( $active_plugins as $plugin_path ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_path );
$slug = str_replace( '/' . basename( $plugin_path ), '', $plugin_path );
$plugins[ $slug ] = array(
'version' => $plugin_info['Version'],
'name' => $plugin_info['Name'],
'plugin_uri' => $plugin_info['PluginURI'],
'author' => $plugin_info['AuthorName'],
'author_uri' => $plugin_info['AuthorURI'],
);
}
unset( $active_plugins, $plugin_path, $plugin_info, $slug );
$data = array(
'site' => array(
'hash' => $hash,
'version' => get_bloginfo( 'version' ),
'multisite' => is_multisite(),
'users' => $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->users INNER JOIN $wpdb->usermeta ON ({$wpdb->users}.ID = {$wpdb->usermeta}.user_id) WHERE 1 = 1 AND ( {$wpdb->usermeta}.meta_key = %s )", 'wp_' . $GLOBALS['blog_id'] . '_capabilities' ) ),
'lang' => get_locale(),
),
'pts' => $pts,
'comments' => array(
'total' => $comments_count->total_comments,
'approved' => $comments_count->approved,
'spam' => $comments_count->spam,
'pings' => $wpdb->get_var( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_type = 'pingback'" ),
),
'options' => apply_filters( 'yoast_tracking_filters', array() ),
'theme' => $theme,
'plugins' => $plugins,
);
$args = array(
'body' => $data,
'blocking' => false,
'sslverify' => false,
);
wp_remote_post( 'https://tracking.yoast.com/', $args );
}
} /* End of class */
/**
* Adds tracking parameters for WP SEO settings. Outside of the main class as the class could also be in use in other plugins.
@@ -179,7 +182,8 @@ if ( ! class_exists( 'Yoast_Tracking' ) ) {
function wpseo_tracking_additions( $options ) {
if ( function_exists( 'curl_version' ) ) {
$curl = curl_version();
} else {
}
else {
$curl = null;
}
@@ -199,23 +203,17 @@ function wpseo_tracking_additions( $options ) {
'wmt_pinterest' => ( ! empty( $opt['pinterestverify'] ) ) ? 1 : 0,
'wmt_yandex' => ( ! empty( $opt['yandexverify'] ) ) ? 1 : 0,
'permalinks_clean' => ( $opt['cleanpermalinks'] == 1 ) ? 1 : 0,
'site_db_charset' => DB_CHARSET,
'webserver_apache' => wpseo_is_apache() ? 1 : 0,
'webserver_apache' => WPSEO_Utils::is_apache() ? 1 : 0,
'webserver_apache_version' => function_exists( 'apache_get_version' ) ? apache_get_version() : 0,
'webserver_nginx' => wpseo_is_nginx() ? 1 : 0,
'webserver_nginx' => WPSEO_Utils::is_nginx() ? 1 : 0,
'webserver_server_software' => $_SERVER['SERVER_SOFTWARE'],
'webserver_gateway_interface' => $_SERVER['GATEWAY_INTERFACE'],
'webserver_server_protocol' => $_SERVER['SERVER_PROTOCOL'],
'php_version' => phpversion(),
'php_max_execution_time' => ini_get( 'max_execution_time' ),
'php_memory_limit' => ini_get( 'memory_limit' ),
'php_open_basedir' => ini_get( 'open_basedir' ),
'php_bcmath_enabled' => extension_loaded( 'bcmath' ) ? 1 : 0,
'php_ctype_enabled' => extension_loaded( 'ctype' ) ? 1 : 0,
'php_curl_enabled' => extension_loaded( 'curl' ) ? 1 : 0,
@@ -0,0 +1,456 @@
<?php
/**
* @package WPSEO\Admin
*/
/**
* Admin form class.
*/
class Yoast_Form {
/**
* @var object Instance of this class
*/
public static $instance;
/**
* @var string
*/
public $option_name;
/**
* @var array
*/
public $options;
/**
* Get the singleton instance of this class
*
* @return object
*/
public static function get_instance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Generates the header for admin pages
*
* @param bool $form Whether or not the form start tag should be included.
* @param string $option The short name of the option to use for the current page.
* @param bool $contains_files Whether the form should allow for file uploads.
* @param bool $option_long_name
*/
public function admin_header( $form = true, $option = 'wpseo', $contains_files = false, $option_long_name = false ) {
if ( ! $option_long_name ) {
$option_long_name = WPSEO_Options::get_group_name( $option );
}
?>
<div class="wrap wpseo-admin-page page-<?php echo $option; ?>">
<?php
/**
* Display the updated/error messages
* Only needed as our settings page is not under options, otherwise it will automatically be included
* @see settings_errors()
*/
require_once( ABSPATH . 'wp-admin/options-head.php' );
?>
<h2 id="wpseo-title"><?php echo esc_html( get_admin_page_title() ); ?></h2>
<div class="wpseo_content_wrapper">
<div class="wpseo_content_cell" id="wpseo_content_top">
<?php
if ( $form === true ) {
$enctype = ( $contains_files ) ? ' enctype="multipart/form-data"' : '';
echo '<form action="' . esc_url( admin_url( 'options.php' ) ) . '" method="post" id="wpseo-conf"' . $enctype . ' accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
settings_fields( $option_long_name );
}
$this->set_option( $option );
}
/**
* Set the option used in output for form elements
*
* @param string $option_name
*/
public function set_option( $option_name ) {
$this->option_name = $option_name;
$this->options = $this->get_option();
}
/**
* Retrieve options based on whether we're on multisite or not.
*
* @since 1.2.4
*
* @return array
*/
private function get_option() {
if ( is_network_admin() ) {
return get_site_option( $this->option_name );
}
return get_option( $this->option_name );
}
/**
* Generates the footer for admin pages
*
* @param bool $submit Whether or not a submit button and form end tag should be shown.
* @param bool $show_sidebar Whether or not to show the banner sidebar - used by premium plugins to disable it
*/
public function admin_footer( $submit = true, $show_sidebar = true ) {
if ( $submit ) {
submit_button();
echo '
</form>';
}
do_action( 'wpseo_admin_footer' );
echo '
</div><!-- end of div wpseo_content_top -->';
if ( $show_sidebar ) {
$this->admin_sidebar();
}
echo '</div><!-- end of div wpseo_content_wrapper -->';
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG === true ) ) {
$xdebug = ( extension_loaded( 'xdebug' ) ? true : false );
echo '
<div id="poststuff">
<div id="wpseo-debug-info" class="postbox">
<h3 class="hndle"><span>' . __( 'Debug Information', 'wordpress-seo' ) . '</span></h3>
<div class="inside">
<h4>' . esc_html( __( 'Current option:', 'wordpress-seo' ) ) . ' <span class="wpseo-debug">' . esc_html( $this->option_name ) . '</span></h4>
' . ( ( $xdebug ) ? '' : '<pre>' );
var_dump( $this->get_option() );
echo '
' . ( ( $xdebug ) ? '' : '</pre>' ) . '
</div>
</div>
</div>';
}
echo '
</div><!-- end of wrap -->';
}
/**
* Generates the sidebar for admin pages.
*/
public function admin_sidebar() {
// No banners in Premium
if ( class_exists( 'WPSEO_Product_Premium' ) ) {
$license_manager = new Yoast_Plugin_License_Manager( new WPSEO_Product_Premium() );
if ( $license_manager->license_is_valid() ) {
return;
}
}
$service_banners = array(
array(
'url' => 'https://yoast.com/hire-us/website-review/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=website-review-banner',
'img' => 'banner-website-review.png',
'alt' => 'Website Review banner',
),
);
$plugin_banners = array(
array(
'url' => 'https://yoast.com/wordpress/plugins/seo-premium/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=premium-seo-banner',
'img' => 'banner-premium-seo.png',
'alt' => 'Banner WordPress SEO Premium',
),
);
if ( ! class_exists( 'wpseo_Video_Sitemap' ) ) {
$plugin_banners[] = array(
'url' => 'https://yoast.com/wordpress/plugins/video-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=video-seo-banner',
'img' => 'banner-video-seo.png',
'alt' => 'Banner WordPress SEO Video SEO extension',
);
}
if ( class_exists( 'Woocommerce' ) && ! class_exists( 'Yoast_WooCommerce_SEO' ) ) {
$plugin_banners[] = array(
'url' => 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=woocommerce-seo-banner',
'img' => 'banner-woocommerce-seo.png',
'alt' => 'Banner WooCommerce SEO plugin',
);
}
if ( ! defined( 'WPSEO_LOCAL_VERSION' ) ) {
$plugin_banners[] = array(
'url' => 'https://yoast.com/wordpress/plugins/local-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=local-seo-banner',
'img' => 'banner-local-seo.png',
'alt' => 'Banner Local SEO plugin',
);
}
if ( ! class_exists( 'WPSEO_News' ) ) {
$plugin_banners[] = array(
'url' => 'https://yoast.com/wordpress/plugins/news-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=news-seo-banner',
'img' => 'banner-news-seo.png',
'alt' => 'Banner News SEO',
);
}
shuffle( $service_banners );
shuffle( $plugin_banners );
?>
<div class="wpseo_content_cell" id="sidebar-container">
<div id="sidebar">
<?php
$service_banner = $service_banners[0];
echo '<a target="_blank" href="' . esc_url( $service_banner['url'] ) . '"><img width="261" height="190" src="' . plugins_url( 'images/' . $service_banner['img'], WPSEO_FILE ) . '" alt="' . esc_attr( $service_banner['alt'] ) . '"/></a><br/><br/>';
$i = 0;
foreach ( $plugin_banners as $banner ) {
if ( $i == 2 ) {
break;
}
echo '<a target="_blank" href="' . esc_url( $banner['url'] ) . '"><img width="261" src="' . plugins_url( 'images/' . $banner['img'], WPSEO_FILE ) . '" alt="' . esc_attr( $banner['alt'] ) . '"/></a><br/><br/>';
$i ++;
}
?>
<strong><?php _e( 'Remove these ads?', 'wordpress-seo' ); ?></strong><br/>
<a target="_blank" href="https://yoast.com/wordpress/plugins/seo-premium/#utm_source=wordpress-seo-config&utm_medium=textlink&utm_campaign=remove-ads-link"><?php _e( 'Upgrade to WordPress SEO Premium &raquo;', 'wordpress-seo' ); ?></a><br/><br/>
</div>
</div>
<?php
}
/**
* Output a label element
*
* @param string $text
* @param array $attr
*/
public function label( $text, $attr ) {
$attr = wp_parse_args( $attr, array(
'class' => 'checkbox',
'close' => true,
'for' => '',
)
);
echo "<label class='" . $attr['class'] . "' for='" . esc_attr( $attr['for'] ) . "'>$text";
if ( $attr['close'] ) {
echo '</label>';
}
}
/**
* Create a Checkbox input field.
*
* @param string $var The variable within the option to create the checkbox for.
* @param string $label The label to show for the variable.
* @param bool $label_left Whether the label should be left (true) or right (false).
*/
public function checkbox( $var, $label, $label_left = false ) {
if ( ! isset( $this->options[ $var ] ) ) {
$this->options[ $var ] = false;
}
if ( $this->options[ $var ] === true ) {
$this->options[ $var ] = 'on';
}
$class = '';
if ( $label_left !== false ) {
if ( ! empty( $label_left ) ) {
$label_left .= ':';
}
$this->label( $label_left, array( 'for' => $var ) );
}
else {
$class = 'double';
}
echo '<input class="checkbox ', esc_attr( $class ), '" type="checkbox" id="', esc_attr( $var ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" value="on"', checked( $this->options[ $var ], 'on', false ), '/>';
if ( ! empty( $label ) ) {
$this->label( $label, array( 'for' => $var ) );
}
echo '<br class="clear" />';
}
/**
* Create a Text input field.
*
* @param string $var The variable within the option to create the text input field for.
* @param string $label The label to show for the variable.
* @param array|string $attr Extra class to add to the input field
*/
public function textinput( $var, $label, $attr = array() ) {
if ( ! is_array( $attr ) ) {
$attr = array(
'class' => $attr,
);
}
$attr = wp_parse_args( $attr, array(
'placeholder' => '',
'class' => '',
) );
$val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
$this->label( $label . ':', array( 'for' => $var ) );
echo '<input class="textinput ' . esc_attr( $attr['class'] ) . ' " placeholder="' . esc_attr( $attr['placeholder'] ) . '" type="text" id="', esc_attr( $var ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" value="', esc_attr( $val ), '"/>', '<br class="clear" />';
}
/**
* Create a textarea.
*
* @param string $var The variable within the option to create the textarea for.
* @param string $label The label to show for the variable.
* @param array $attr The CSS class to assign to the textarea.
*/
public function textarea( $var, $label, $attr = array() ) {
if ( ! is_array( $attr ) ) {
$attr = array(
'class' => $attr,
);
}
$attr = wp_parse_args( $attr, array(
'cols' => '',
'rows' => '',
'class' => '',
) );
$val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
$this->label( $label . ':', array( 'for' => $var, 'class' => 'textinput' ) );
echo '<textarea cols="' . esc_attr( $attr['cols'] ) . '" rows="' . esc_attr( $attr['rows'] ) . '" class="textinput ' . esc_attr( $attr['class'] ) . '" id="' . esc_attr( $var ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $var ) . ']">' . esc_textarea( $val ) . '</textarea>' . '<br class="clear" />';
}
/**
* Create a hidden input field.
*
* @param string $var The variable within the option to create the hidden input for.
* @param string $id The ID of the element
*/
public function hidden( $var, $id = '' ) {
$val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
if ( is_bool( $val ) ) {
$val = ( $val === true ) ? 'true' : 'false';
}
if ( '' === $id ) {
$id = 'hidden_' . $var;
}
echo '<input type="hidden" id="' . esc_attr( $id ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $var ) . ']" value="' . esc_attr( $val ) . '"/>';
}
/**
* Create a Select Box.
*
* @param string $var The variable within the option to create the select for.
* @param string $label The label to show for the variable.
* @param array $values The select options to choose from.
*/
public function select( $var, $label, $values ) {
if ( ! is_array( $values ) || $values === array() ) {
return;
}
$val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
$this->label( $label . ':', array( 'for' => $var, 'class' => 'select' ) );
echo '<select class="select" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" id="', esc_attr( $var ), '">';
foreach ( $values as $value => $label ) {
if ( ! empty( $label ) ) {
echo '<option value="', esc_attr( $value ), '"', selected( $val, $value, false ), '>', $label, '</option>';
}
}
echo '</select>';
echo '<br class="clear"/>';
}
/**
* Create a File upload field.
*
* @param string $var The variable within the option to create the file upload field for.
* @param string $label The label to show for the variable.
*/
public function file_upload( $var, $label ) {
$val = '';
if ( isset( $this->options[ $var ] ) && is_array( $this->options[ $var ] ) ) {
$val = $this->options[ $var ]['url'];
}
$var_esc = esc_attr( $var );
$this->label( $label . ':', array( 'for' => $var, 'class' => 'select' ) );
echo '<input type="file" value="' . esc_attr( $val ) . '" class="textinput" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" id="' . $var_esc . '"/>';
// Need to save separate array items in hidden inputs, because empty file inputs type will be deleted by settings API.
if ( ! empty( $this->options[ $var ] ) ) {
$this->hidden( 'file', $this->option_name . '_file' );
$this->hidden( 'url', $this->option_name . '_url' );
$this->hidden( 'type', $this->option_name . '_type' );
}
echo '<br class="clear"/>';
}
/**
* Media input
*
* @param string $var
* @param string $label
*/
public function media_input( $var, $label ) {
$val = '';
if ( isset( $this->options[ $var ] ) ) {
$val = $this->options[ $var ];
}
$var_esc = esc_attr( $var );
$this->label( $label . ':', array( 'for' => 'wpseo_' . $var, 'class' => 'select' ) );
echo '<input class="textinput" id="wpseo_', $var_esc, '" type="text" size="36" name="', esc_attr( $this->option_name ), '[', $var_esc, ']" value="', esc_attr( $val ), '" />';
echo '<input id="wpseo_', $var_esc, '_button" class="wpseo_image_upload_button button" type="button" value="', __( 'Upload Image', 'wordpress-seo' ), '" />';
echo '<br class="clear"/>';
}
/**
* Create a Radio input field.
*
* @param string $var The variable within the option to create the file upload field for.
* @param array $values The radio options to choose from.
* @param string $label The label to show for the variable.
*/
public function radio( $var, $values, $label ) {
if ( ! is_array( $values ) || $values === array() ) {
return;
}
if ( ! isset( $this->options[ $var ] ) ) {
$this->options[ $var ] = false;
}
$var_esc = esc_attr( $var );
echo '<br/><div class="wpseo_radio_block" id="' . $var_esc . '">';
if ( is_string( $label ) && $label !== '' ) {
$this->label( $label . ':', array( 'class' => 'select' ) );
}
foreach ( $values as $key => $value ) {
$key_esc = esc_attr( $key );
echo '<input type="radio" class="radio" id="' . $var_esc . '-' . $key_esc . '" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" value="' . $key_esc . '" ' . checked( $this->options[ $var ], $key_esc, false ) . ' />';
$this->label( $value, array( 'for' => $var_esc . '-' . $key_esc, 'class' => 'radio' ) );
}
echo '<div class="clear"></div>';
echo '</div><br/>';
}
}
@@ -1,11 +1,25 @@
<?php
/**
* @package WPSEO\Admin
*/
/**
* Handles notifications storage and display.
*/
class Yoast_Notification_Center {
const TRANSIENT_KEY = 'yoast_notifications';
/**
* The singleton instance of this object
*
* @var \Yoast_Notification_Center
*/
private static $instance = null;
/**
* @var array
*/
private $notifications = array();
/**
@@ -105,10 +119,8 @@ class Yoast_Notification_Center {
}
// Set the cookie with notifications
set_transient( self::TRANSIENT_KEY, json_encode( $arr_notifications ), MINUTE_IN_SECONDS * 10 );
set_transient( self::TRANSIENT_KEY, json_encode( $arr_notifications ), ( MINUTE_IN_SECONDS * 10 ) );
}
}
/**
@@ -134,7 +146,6 @@ class Yoast_Notification_Center {
// Clear the local stored notifications
$this->clear_notifications();
}
/**
@@ -1,8 +1,22 @@
<?php
/**
* @package WPSEO\Admin
* @since 1.5.3
*/
/**
* Implements individual notification.
*/
class Yoast_Notification {
/**
* @var string The notification message
*/
private $message;
/**
* @var string The notification type, i.e. 'updated' or 'error'
*/
private $type;
/**
@@ -60,7 +74,7 @@ class Yoast_Notification {
* Output the message
*/
public function output() {
echo '<div class="yoast-notice ' . $this->get_type() . '">' . wpautop( $this->get_message() ) . '</div>' . PHP_EOL;
echo '<div class="yoast-notice ', esc_attr( $this->get_type() ), '">', wpautop( $this->get_message() ), '</div>', PHP_EOL;
}
}
@@ -1,251 +1,269 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
* @since 1.7.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Base class for handling plugin conflicts.
*/
class Yoast_Plugin_Conflict {
if ( ! class_exists( 'Yoast_Plugin_Conflict' ) ) {
/**
* The plugins must be grouped per section.
*
* It's possible to check for each section if there are conflicting plugin
*
* @var array
*/
protected $plugins = array();
class Yoast_Plugin_Conflict {
/**
* All the current active plugins will be stored in this private var
*
* @var array
*/
protected $all_active_plugins = array();
/**
* The plugins must be grouped per section.
*
* It's possible to check for each section if there are conflicting plugin
*
* @var array
*/
protected $plugins = array();
/**
* After searching for active plugins that are in $this->plugins the active plugins will be stored in this
* property
*
* @var array
*/
protected $active_plugins = array();
/**
* All the current active plugins will be stored in this private var
*
* @var array
*/
protected $all_active_plugins = array();
/**
* Property for holding instance of itself
*
* @var Yoast_Plugin_Conflict
*/
protected static $instance;
/**
* After searching for active plugins that are in $this->plugins the active plugins will be stored in this
* property
*
* @var array
*/
protected $active_plugins = array();
/**
* For the use of singleton pattern. Create instance of itself and return his instance
*
* @param string $class_name Give the classname to initialize. If classname is false (empty) it will use it's own __CLASS__
*
* @return Yoast_Plugin_Conflict
*/
public static function get_instance( $class_name = '' ) {
/**
* Property for holding instance of itself
*
* @var Yoast_Plugin_Conflict
*/
protected static $instance;
/**
* For the use of singleton pattern. Create instance of itself and return his instance
*
* @param bool|string $classname Give the classname to initialize. If classname is false (empty) it will use it's own __CLASS__
*
* @return Yoast_Plugin_Conflict
*/
public static function get_instance( $class_name = false ) {
if ( is_null( self::$instance ) ) {
if ( empty( $class_name ) ) {
$class_name = __CLASS__;
}
self::$instance = new $class_name();
if ( is_null( self::$instance ) ) {
if ( ! is_string( $class_name ) || $class_name === '' ) {
$class_name = __CLASS__;
}
return self::$instance;
self::$instance = new $class_name();
}
/**
* Setting instance, all active plugins and search for active plugins
*
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*
*/
protected function __construct() {
// Set active plugins
$this->all_active_plugins = get_option( 'active_plugins' );
return self::$instance;
}
// Search for active plugins
$this->search_active_plugins();
/**
* Setting instance, all active plugins and search for active plugins
*
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*
*/
protected function __construct() {
// Set active plugins
$this->all_active_plugins = get_option( 'active_plugins' );
// Search for active plugins
$this->search_active_plugins();
}
/**
* Check if there are conflicting plugins for given $plugin_section
*
* @param string $plugin_section
*
* @return bool
*/
public function check_for_conflicts( $plugin_section ) {
static $sections_checked;
if ( $sections_checked == null ) {
$sections_checked = array();
}
/**
* Check if there are conflicting plugins for given $plugin_section
*
* @param string $plugin_section
*
* @return bool
*/
public function check_for_conflicts( $plugin_section ) {
if ( ! in_array( $plugin_section, $sections_checked ) ) {
$sections_checked[] = $plugin_section;
$has_conflicts = ( ! empty( $this->active_plugins[ $plugin_section ] ) );
static $sections_checked;
return $has_conflicts;
}
else {
return false;
}
}
if ( $sections_checked == null ) {
$sections_checked = array();
}
/**
* Get plugin name from file
*
* @param string $plugin
*
* @return bool
*/
private function get_plugin_name( $plugin ) {
$plugin_details = get_plugin_data( ABSPATH . '/wp-content/plugins/' . $plugin );
if ( ! in_array($plugin_section, $sections_checked ) ) {
$sections_checked[] = $plugin_section;
$has_conflicts = ( ! empty( $this->active_plugins[$plugin_section] ) );
if ( $plugin_details['Name'] != '' ) {
return $plugin_details['Name'];
}
return false;
}
return $has_conflicts;
}
else {
return false;
}
/**
* Getting all the conflicting plugins and return them as a string.
*
* This method will loop through all conflicting plugins to get the details of each plugin. The plugin name
* will be taken from the details to parse a comma separated string, which can be use for by example a notice
*
* @param string $plugin_section
*
* @return string
*/
public function get_conflicting_plugins_as_string( $plugin_section ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
/**
* Getting all the conflicting plugins and return them as a string.
*
* This method will loop through all conflicting plugins to get the details of each plugin. The plugin name
* will be taken from the details to parse a comma separated string, which can be use for by example a notice
*
* @param string $plugin_section
*
* @return string
*/
public function get_conflicting_plugins_as_string( $plugin_section ) {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
// Getting the active plugins by given section
$plugins = $this->active_plugins[ $plugin_section ];
// Getting the active plugins by given section
$plugins = $this->active_plugins[$plugin_section];
$plugin_names = array();
foreach ( $plugins AS $plugin ) {
$plugin_details = get_plugin_data( ABSPATH . '/wp-content/plugins/' . $plugin );
if ( $plugin_details['Name'] != '' ) {
$plugin_names[] = $plugin_details['Name'];
}
}
if ( ! empty( $plugin_names ) ) {
return implode( ', ', $plugin_names );
$plugin_names = array();
foreach ( $plugins as $plugin ) {
if ( $name = $this->get_plugin_name( $plugin ) ) {
$plugin_names[] = '<em>' . $name . '</em>';
}
}
unset( $plugins, $plugin );
/**
* Checks for given $plugin_sections for conflicts
*
* @param array $plugin_sections
*/
public function check_plugin_conflicts( $plugin_sections ) {
foreach ( $plugin_sections AS $plugin_section => $readable_plugin_section ) {
// Check for conflicting plugins and show error if there are conflicts
if ( $this->check_for_conflicts( $plugin_section ) ) {
$this->set_error( $plugin_section, $readable_plugin_section );
}
if ( ! empty( $plugin_names ) ) {
return implode( ' &amp; ', $plugin_names );
}
}
/**
* Checks for given $plugin_sections for conflicts
*
* @param array $plugin_sections
*/
public function check_plugin_conflicts( $plugin_sections ) {
foreach ( $plugin_sections as $plugin_section => $readable_plugin_section ) {
// Check for conflicting plugins and show error if there are conflicts
if ( $this->check_for_conflicts( $plugin_section ) ) {
$this->set_error( $plugin_section, $readable_plugin_section );
}
}
}
/**
* Setting an error on the screen
*
* @param string $plugin_section
* @param string $readable_plugin_section This is the value for the translation
*/
protected function set_error( $plugin_section, $readable_plugin_section ) {
/**
* Setting an error on the screen
*
* @param string $plugin_section
* @param string $readable_plugin_section This is the value for the translation
*/
protected function set_error( $plugin_section, $readable_plugin_section ) {
$plugins_as_string = $this->get_conflicting_plugins_as_string( $plugin_section );
$error_message = sprintf( __( 'The following plugins might cause (%1s) issues with Yoast WordPress SEO: %2s', 'wordpress-seo' ), $readable_plugin_section, $plugins_as_string );
$plugins_as_string = $this->get_conflicting_plugins_as_string( $plugin_section );
$error_message = '<h3>' . __( 'Warning!', 'wordpress-seo' ) . '</h3>';
// Add the message to the notifications center
Yoast_Notification_Center::get()->add_notification( new Yoast_Notification( $error_message, 'error' ) );
/* translators: %s: 'Facebook & Open Graph' plugin name(s) of possibly conflicting plugin(s) */
$error_message .= '<p>' . sprintf( __( 'The %s plugin(s) might cause issues when used in conjunction with Yoast WordPress SEO.', 'wordpress-seo' ), $plugins_as_string ) . '</p>';
$error_message .= sprintf( $readable_plugin_section, $plugins_as_string ) . '<br/><br/>';
$error_message .= '<p><strong>' . __( 'Recommended solution', 'wordpress-seo' ) . '</strong><br/>';
/* translators: %s: 'Facebook & Open Graph' plugin name(s) of possibly conflicting plugin(s) */
$error_message .= sprintf( __( 'We recommend you deactivate %s and have another look at your WordPress SEO configuration using the button above.', 'wordpress-seo' ), $plugins_as_string ) . '</p>';
foreach ( $this->active_plugins[ $plugin_section ] as $plugin_file ) {
/* translators: %s: 'Facebook' plugin name of possibly conflicting plugin */
$error_message .= '<a target="_blank" class="button-primary" href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=all', 'deactivate-plugin_' . $plugin_file ) . '">' . sprintf( __( 'Deactivate %s', 'wordpress-seo' ), $this->get_plugin_name( $plugin_file ) ) . '</a> ';
}
$error_message .= '<p class="alignright"><small>' . __( 'This warning is generated by WordPress SEO by Yoast.', 'wordpress-seo' ) . '</small></p><div class="clear"></div>';
/**
* Loop through the $this->plugins to check if one of the plugins is active.
*
* This method will store the active plugins in $this->active_plugins.
*/
protected function search_active_plugins() {
foreach ( $this->plugins AS $plugin_section => $plugins ) {
$this->check_plugins_active( $plugins, $plugin_section );
// Add the message to the notifications center
Yoast_Notification_Center::get()->add_notification( new Yoast_Notification( $error_message, 'error' ) );
}
/**
* Loop through the $this->plugins to check if one of the plugins is active.
*
* This method will store the active plugins in $this->active_plugins.
*/
protected function search_active_plugins() {
foreach ( $this->plugins as $plugin_section => $plugins ) {
$this->check_plugins_active( $plugins, $plugin_section );
}
}
/**
* Loop through plugins and check if each plugin is active
*
* @param array $plugins
* @param string $plugin_section
*/
protected function check_plugins_active( $plugins, $plugin_section ) {
foreach ( $plugins as $plugin ) {
if ( $this->check_plugin_is_active( $plugin ) ) {
$this->add_active_plugin( $plugin_section, $plugin );
}
}
}
/**
* Loop through plugins and check if each plugin is active
*
* @param array $plugins
* @param string $plugin_section
*/
protected function check_plugins_active( $plugins, $plugin_section ) {
foreach ( $plugins AS $plugin ) {
if ( $this->check_plugin_is_active( $plugin ) ) {
$this->add_active_plugin( $plugin_section, $plugin );
}
}
/**
* Check if given plugin exists in array with all_active_plugins
*
* @param string $plugin
*
* @return bool
*/
protected function check_plugin_is_active( $plugin ) {
return in_array( $plugin, $this->all_active_plugins );
}
/**
* Add plugin to the list of active plugins.
*
* This method will check first if key $plugin_section exists, if not it will create an empty array
* If $plugin itself doesn't exist it will be added.
*
* @param string $plugin_section
* @param string $plugin
*/
protected function add_active_plugin( $plugin_section, $plugin ) {
if ( ! array_key_exists( $plugin_section, $this->active_plugins ) ) {
$this->active_plugins[ $plugin_section ] = array();
}
/**
* Check if given plugin exists in array with all_active_plugins
*
* @param string $plugin
*
* @return bool
*/
protected function check_plugin_is_active( $plugin ) {
$is_plugin_active = in_array( $plugin, $this->all_active_plugins );
return $is_plugin_active;
if ( ! in_array( $plugin, $this->active_plugins[ $plugin_section ] ) ) {
$this->active_plugins[ $plugin_section ][] = $plugin;
}
}
/**
* Add plugin to the list of active plugins.
*
* This method will check first if key $plugin_section exists, if not it will create an empty array
* If $plugin itself doesn't exist it will be added.
*
* @param string $plugin_section
* @param string $plugin
*/
protected function add_active_plugin( $plugin_section, $plugin ) {
/**
* Search in $this->plugins for the given $plugin
*
* If there is a result it will return the plugin category
*
* @param string $plugin
*
* @return int|string
*/
protected function find_plugin_category( $plugin ) {
if ( ! array_key_exists( $plugin_section, $this->active_plugins ) ) {
$this->active_plugins[$plugin_section] = array();
foreach ( $this->plugins as $plugin_section => $plugins ) {
if ( in_array( $plugin, $plugins ) ) {
return $plugin_section;
}
if ( ! in_array( $plugin, $this->active_plugins[$plugin_section] ) ) {
$this->active_plugins[$plugin_section][] = $plugin;
}
}
/**
* Search in $this->plugins for the given $plugin
*
* If there is a result it will return the plugin category
*
* @param string $plugin
*
* @return int|string
*/
protected function find_plugin_category( $plugin ) {
foreach ( $this->plugins AS $plugin_section => $plugins ) {
if ( in_array( $plugin, $plugins ) ) {
return $plugin_section;
}
}
}
}
}
}
@@ -1,675 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
@@ -1,28 +0,0 @@
[![Code Climate](https://codeclimate.com/github/Yoast/i18n-module/badges/gpa.svg)](https://codeclimate.com/github/Yoast/i18n-module)
# Yoast i18n module
Promote your own translation site for people who are using your plugin in another language than `en_US`.
## Example of the rendered promo box
![Example promo box](http://uploads.yoast.nl/i18n-promo-box_1A1B3FFF.png)
The image, the name of your plugin and the name of your translation project are all configurable (see example below). The name of the language is retrieved from your GlotPress install, as is the percentage translated. The box doesn't display when a language has been translated for 90% or more.
## How to use this module
Just include the library as a submodule, make sure the class is loaded and instantiate it like this:
```php
$wpseo_i18n = new yoast_i18n(
array(
'textdomain' => 'wordpress-seo',
'project_slug' => 'wordpress-seo',
'plugin_name' => 'WordPress SEO by Yoast',
'hook' => 'wpseo_admin_footer',
'glotpress_url' => 'http://translate.yoast.com',
'glotpress_name' => 'Yoast Translate',
'glotpress_logo' => 'https://cdn.yoast.com/wp-content/uploads/i18n-images/Yoast_Translate.svg',
'register_url ' => 'http://translate.yoast.com/projects#utm_source=plugin&utm_medium=promo-box&utm_campaign=i18n-promo',
)
);
```
@@ -1,278 +0,0 @@
<?php
/**
* This class defines a promo box and checks your translation site's API for stats about it, then shows them to the user.
*/
class yoast_i18n {
/**
* Your translation site's logo
*
* @var string
*/
private $glotpress_logo;
/**
* Your translation site's name
*
* @var string
*/
private $glotpress_name;
/**
* Your translation site's URL
*
* @var string
*/
private $glotpress_url;
/**
* Hook where you want to show the promo box
*
* @var string
*/
private $hook;
/**
* Will contain the site's locale
*
* @access private
* @var string
*/
private $locale;
/**
* Will contain the locale's name, obtained from yoru translation site
*
* @access private
* @var string
*/
private $locale_name;
/**
* Will contain the percentage translated for the plugin translation project in the locale
*
* @access private
* @var int
*/
private $percent_translated;
/**
* Name of your plugin
*
* @var string
*/
private $plugin_name;
/**
* Project slug for the project on your translation site
*
* @var string
*/
private $project_slug;
/**
* URL to point to for registration links
*
* @var string
*/
private $register_url;
/**
* Your plugins textdomain
*
* @var string
*/
private $textdomain;
/**
* Indicates whether there's a translation available at all.
*
* @access private
* @var bool
*/
private $translation_exists;
/**
* Indicates whether the translation's loaded.
*
* @access private
* @var bool
*/
private $translation_loaded;
/**
* Class constructor
*
* @param array $args Contains the settings for the class.
*/
public function __construct( $args ) {
if ( ! is_admin() ) {
return;
}
$this->locale = get_locale();
if ( 'en_US' === $this->locale ) {
return;
}
$this->init( $args );
if ( ! $this->hide_promo() ) {
add_action( $this->hook, array( $this, 'promo' ) );
}
}
/**
* This is where you decide where to display the messages and where you set the plugin specific variables.
*
* @access private
*
* @param array $args
*/
private function init( $args ) {
foreach ( $args as $key => $arg ) {
$this->$key = $arg;
}
}
/**
* Check whether the promo should be hidden or not
*
* @access private
*
* @return bool
*/
private function hide_promo() {
$hide_promo = get_transient( 'yoast_i18n_' . $this->project_slug . '_promo_hide' );
if ( ! $hide_promo ) {
if ( filter_input( INPUT_GET, 'remove_i18n_promo', FILTER_NULL_ON_FAILURE ) ) {
// No expiration time, so this would normally not expire, but it wouldn't be copied to other sites etc.
set_transient( 'yoast_i18n_' . $this->project_slug . '_promo_hide', true );
$hide_promo = true;
}
}
return $hide_promo;
}
/**
* Generates a promo message
*
* @access private
*
* @return bool|string $message
*/
private function promo_message() {
$message = false;
if ( $this->translation_loaded && $this->percent_translated < 90 ) {
$message = __( 'As you can see, there is a translation of this plugin in %1$s. This translation is currently %3$d%% complete. We need your help to make it complete and to fix any errors. Please register at %4$s to help complete the translation to %1$s!', $this->textdomain );
} else if ( ! $this->translation_loaded && $this->translation_exists ) {
$message = __( 'You\'re using WordPress in %1$s. While %2$s has been translated to %1$s for %3$d%%, it\'s not been shipped with the plugin yet. You can help! Register at %4$s to help complete the translation to %1$s!', $this->textdomain );
} else if ( ! $this->translation_loaded && ! $this->translation_exists ) {
$message = __( 'You\'re using WordPress in a language we don\'t support yet. We\'d love for %2$s to be translated in that language too, but unfortunately, it isn\'t right now. You can change that! Register at %4$s to help translate it!', $this->textdomain );
}
$registration_link = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $this->register_url ), esc_html( $this->glotpress_name ) );
$message = sprintf( $message, esc_html( $this->locale_name ), esc_html( $this->plugin_name ), $this->percent_translated, $registration_link );
return $message;
}
/**
* Outputs a promo box
*/
public function promo() {
$this->translation_details();
$message = $this->promo_message();
if ( $message ) {
echo '<div id="i18n_promo_box" style="border:1px solid #ccc;background-color:#fff;padding:10px;max-width:650px;">';
echo '<a href="' . add_query_arg( array( 'remove_i18n_promo' => '1' ) ) . '" style="color:#333;text-decoration:none;font-weight:bold;font-size:16px;border:1px solid #ccc;padding:1px 4px;" class="alignright">X</a>';
echo '<h2>' . sprintf( __( 'Translation of %s', $this->textdomain ), $this->plugin_name ) . '</h2>';
if ( isset( $this->glotpress_logo ) && '' != $this->glotpress_logo ) {
echo '<a href="' . $this->register_url . '"><img class="alignright" style="margin:15px 5px 5px 5px;width:200px;" src="' . $this->glotpress_logo . '" alt="' . $this->glotpress_name . '"/></a>';
}
echo '<p>' . $message . '</p>';
echo '<p><a href="' . $this->register_url . '">' . __( 'Register now &raquo;', $this->textdomain ) . '</a></p>';
echo '</div>';
}
}
/**
* Try to find the transient for the translation set or retrieve them.
*
* @access private
*
* @return object|null
*/
private function find_or_initialize_translation_details() {
$set = get_transient( 'yoast_i18n_' . $this->project_slug );
if ( ! $set ) {
$set = $this->retrieve_translation_details();
set_transient( 'yoast_i18n_' . $this->project_slug, $set, DAY_IN_SECONDS );
}
return $set;
}
/**
* Try to get translation details from cache, otherwise retrieve them, then parse them.
*
* @access private
*/
private function translation_details() {
$set = $this->find_or_initialize_translation_details();
$this->translation_exists = ! is_null( $set );
$this->translation_loaded = is_textdomain_loaded( $this->textdomain );
$this->parse_translation_set( $set );
}
/**
* Retrieve the translation details from Yoast Translate
*
* @access private
*
* @return object|null
*/
private function retrieve_translation_details() {
$api_url = trailingslashit( $this->glotpress_url ) . 'api/projects/' . $this->project_slug;
$resp = wp_remote_get( $api_url );
$body = wp_remote_retrieve_body( $resp );
unset( $resp );
if ( $body ) {
$body = json_decode( $body );
foreach ( $body->translation_sets as $set ) {
if ( $this->locale == $set->wp_locale ) {
return $set;
}
}
}
return null;
}
/**
* Set the needed private variables based on the results from Yoast Translate
*
* @param object $set The translation set
*
* @access private
*/
private function parse_translation_set( $set ) {
if ( $this->translation_exists ) {
$this->locale_name = $set->name;
$this->percent_translated = $set->percent_translated;
} else {
$this->locale_name = '';
$this->percent_translated = '';
}
}
}
@@ -1,21 +0,0 @@
Yoast License Manager
=====================
This library will take care of the following.
- Managing license related options
- Setting license key from a constant
- Obfuscasting (valid) license keys
- Remote license activation / deactivation
- Checking for plugin or theme updates
## Usage
### Inside Plugins
A sample plugin is included, [have a look at its source](https://github.com/Yoast/License-Manager/blob/master/samples/sample-plugin.php).
### Inside Themes
A sample theme `functions.php` file is included, [have a look here](https://github.com/Yoast/License-Manager/blob/master/samples/sample-theme-functions.php).
@@ -1,140 +0,0 @@
<?php
if( ! class_exists( "Yoast_API_Request", false ) ) {
/**
* Handles requests to the Yoast EDD API
*/
class Yoast_API_Request {
/**
* @var string Request URL
*/
private $url = '';
/**
* @var array Request parameters
*/
private $args = array(
'method' => 'GET',
'timeout' => 10,
'sslverify' => false,
'headers' => array(
'Accept-Encoding' => '*',
'X-Yoast-EDD' => '1'
)
);
/**
* @var boolean
*/
private $success = false;
/**
* @var mixed
*/
private $response;
/**
* @var string
*/
private $error_message = '';
/**
* Constructor
*
* @param string url
* @param array $args
*/
public function __construct( $url, array $args = array() ) {
// set api url
$this->url = $url;
// set request args (merge with defaults)
$this->args = wp_parse_args( $args, $this->args );
// fire the request
$this->success = $this->fire();
}
/**
* Fires the request, automatically called from constructor
*
* @return boolean
*/
private function fire() {
// fire request to shop
$response = wp_remote_request( $this->url, $this->args );
// validate raw response
if( $this->validate_raw_response( $response ) === false ) {
return false;
}
// decode the response
$this->response = json_decode( wp_remote_retrieve_body( $response ) );
// response should be an object
if( ! is_object( $this->response ) ) {
$this->error_message = 'No JSON object was returned.';
return false;
}
return true;
}
/**
* @param object $response
* @return boolean
*/
private function validate_raw_response( $response ) {
// make sure response came back okay
if( is_wp_error( $response ) ) {
$this->error_message = $response->get_error_message();
return false;
}
// check response code, should be 200
$response_code = wp_remote_retrieve_response_code( $response );
if( false === strstr( $response_code, '200' ) ) {
$response_message = wp_remote_retrieve_response_message( $response );
$this->error_message = "{$response_code} {$response_message}";
return false;
}
return true;
}
/**
* Was a valid response returned?
*
* @return boolean
*/
public function is_valid() {
return ( $this->success === true );
}
/**
* @return string
*/
public function get_error_message() {
return $this->error_message;
}
/**
* @return object
*/
public function get_response() {
return $this->response;
}
}
}
@@ -1,570 +0,0 @@
<?php
if( ! interface_exists( 'iYoast_License_Manager', false ) ) {
interface iYoast_License_Manager {
public function specific_hooks();
public function setup_auto_updater();
}
}
if( ! class_exists( 'Yoast_License_Manager', false ) ) {
/**
* Class Yoast_License_Manager
*
* @todo Maybe create a license class that contains key and option
* @todo Not sure if Yoast_License_Manager is a good name for this class, it's more managing the product (plugin or theme)
*/
abstract class Yoast_License_Manager implements iYoast_License_Manager {
/**
* @const VERSION The version number of the License_Manager class
*/
const VERSION = 1;
/**
* @var Yoast_License The license
*/
protected $product;
/**
* @var string
*/
private $license_constant_name = '';
/**
* @var boolean True if license is defined with a constant
*/
private $license_constant_is_defined = false;
/**
* @var boolean True if remote license activation just failed
*/
private $remote_license_activation_failed = false;
/**
* @var array Array of license related options
*/
private $options = array();
/**
* @var string Used to prefix ID's, option names, etc..
*/
protected $prefix;
/**
* @var bool Boolean indicating whether this plugin is network activated
*/
protected $is_network_activated = false;
/**
* Constructor
*
* @param Yoast_Product $product
*/
public function __construct( Yoast_Product $product ) {
// Set the license
$this->product = $product;
// set prefix
$this->prefix = sanitize_title_with_dashes( $this->product->get_item_name() . '_', null, 'save' );
// maybe set license key from constant
$this->maybe_set_license_key_from_constant();
}
/**
* Setup hooks
*
*/
public function setup_hooks() {
// show admin notice if license is not active
add_action( 'admin_notices', array( $this, 'display_admin_notices' ) );
// catch POST requests from license form
add_action( 'admin_init', array( $this, 'catch_post_request') );
// setup item type (plugin|theme) specific hooks
$this->specific_hooks();
// setup the auto updater
$this->setup_auto_updater();
}
/**
* Display license specific admin notices, namely:
*
* - License for the product isn't activated
* - External requests are blocked through WP_HTTP_BLOCK_EXTERNAL
*/
public function display_admin_notices() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
// show notice if license is invalid
if( ! $this->license_is_valid() ) {
if( $this->get_license_key() == '' ) {
$message = '<b>Warning!</b> You didn\'t set your %s license key yet, which means you\'re missing out on updates and support! <a href="%s">Enter your license key</a> or <a href="%s" target="_blank">get a license here</a>.';
} else {
$message = '<b>Warning!</b> Your %s license is inactive which means you\'re missing out on updates and support! <a href="%s">Activate your license</a> or <a href="%s" target="_blank">get a license here</a>.';
}
?>
<div class="error">
<p><?php printf( __( $message, $this->product->get_text_domain() ), $this->product->get_item_name(), $this->product->get_license_page_url(), $this->product->get_tracking_url( 'activate-license-notice' ) ); ?></p>
</div>
<?php
}
// show notice if external requests are blocked through the WP_HTTP_BLOCK_EXTERNAL constant
if( defined( "WP_HTTP_BLOCK_EXTERNAL" ) && WP_HTTP_BLOCK_EXTERNAL === true ) {
// check if our API endpoint is in the allowed hosts
$host = parse_url( $this->product->get_api_url(), PHP_URL_HOST );
if( ! defined( "WP_ACCESSIBLE_HOSTS" ) || stristr( WP_ACCESSIBLE_HOSTS, $host ) === false ) {
?>
<div class="error">
<p><?php printf( __( '<b>Warning!</b> You\'re blocking external requests which means you won\'t be able to get %s updates. Please add %s to %s.', $this->product->get_text_domain() ), $this->product->get_item_name(), '<strong>' . $host . '</strong>', '<code>WP_ACCESSIBLE_HOSTS</code>'); ?></p>
</div>
<?php
}
}
}
/**
* Set a notice to display in the admin area
*
* @param string $type error|updated
* @param string $message The message to display
*/
protected function set_notice( $message, $success = true ) {
$css_class = ( $success ) ? 'updated' : 'error';
add_settings_error( $this->prefix . 'license', 'license-notice', $message, $css_class );
}
/**
* Remotely activate License
* @return boolean True if the license is now activated, false if not
*/
public function activate_license() {
$result = $this->call_license_api( 'activate' );
if( $result ) {
// story expiry date
if( isset( $result->expires ) ) {
$this->set_license_expiry_date( $result->expires );
$expiry_date = strtotime( $result->expires );
} else {
$expiry_date = false;
}
// show success notice if license is valid
if($result->license === 'valid') {
$message = sprintf( __( "Your %s license has been activated. ", $this->product->get_text_domain() ), $this->product->get_item_name() );
// show a custom notice if users have an unlimited license
if( $result->license_limit == 0 ) {
$message .= __( "You have an unlimited license. ", $this->product->get_text_domain() );
} else {
$message .= sprintf( __( "You have used %d/%d activations. ", $this->product->get_text_domain() ), $result->site_count, $result->license_limit );
}
// add upgrade notice if user has less than 3 activations left
if( $result->license_limit > 0 && ( $result->license_limit - $result->site_count ) <= 3 ) {
$message .= sprintf( __( '<a href="%s">Did you know you can upgrade your license?</a>', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-nearing-limit-notice' ) );
// add extend notice if license is expiring in less than 1 month
} elseif( $expiry_date !== false && $expiry_date < strtotime( "+1 month" ) ) {
$days_left = round( ( $expiry_date - strtotime( "now" ) ) / 86400 );
$message .= sprintf( __( '<a href="%s">Your license is expiring in %d days, would you like to extend it?</a>', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-expiring-notice' ), $days_left );
}
$this->set_notice( $message, true );
} else {
if( isset($result->error) && $result->error === 'no_activations_left' ) {
// show notice if user is at their activation limit
$this->set_notice( sprintf( __('You\'ve reached your activation limit. You must <a href="%s">upgrade your license</a> to use it on this site.', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-at-limit-notice' ) ), false );
} elseif( isset($result->error) && $result->error == "expired" ) {
// show notice if the license is expired
$this->set_notice( sprintf( __('Your license has expired. You must <a href="%s">extend your license</a> in order to use it again.', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-expired-notice' ) ), false );
} else {
// show a general notice if it's any other error
$this->set_notice( __( "Failed to activate your license, your license key seems to be invalid.", $this->product->get_text_domain() ), false );
}
$this->remote_license_activation_failed = true;
}
$this->set_license_status( $result->license );
}
return ( $this->license_is_valid() );
}
/**
* Remotely deactivate License
* @return boolean True if the license is now deactivated, false if not
*/
public function deactivate_license () {
$result = $this->call_license_api( 'deactivate' );
if( $result ) {
// show notice if license is deactivated
if( $result->license === 'deactivated' ) {
$this->set_notice( sprintf( __( "Your %s license has been deactivated.", $this->product->get_text_domain() ), $this->product->get_item_name() ) );
} else {
$this->set_notice( sprintf( __( "Failed to deactivate your %s license.", $this->product->get_text_domain() ), $this->product->get_item_name() ), false );
}
$this->set_license_status( $result->license );
}
return ( $this->get_license_status() === 'deactivated' );
}
/**
* @param string $action activate|deactivate
* @return mixed
*/
protected function call_license_api( $action ) {
// don't make a request if license key is empty
if( $this->get_license_key() === '' ) {
return false;
}
// data to send in our API request
$api_params = array(
'edd_action' => $action . '_license',
'license' => $this->get_license_key(),
'item_name' => urlencode( trim( $this->product->get_item_name() ) ),
'url' => get_option( 'home' ) // grab the URL straight from the option to prevent filters from breaking it.
);
// create api request url
$url = add_query_arg( $api_params, $this->product->get_api_url() );
require_once dirname( __FILE__ ) . '/class-api-request.php';
$request = new Yoast_API_Request( $url );
if( $request->is_valid() !== true ) {
$this->set_notice( sprintf( __( "Request error: \"%s\" (%scommon license notices%s)", $this->product->get_text_domain() ), $request->get_error_message(), '<a href="http://kb.yoast.com/article/13-license-activation-notices">', '</a>' ), false );
}
// get response
$response = $request->get_response();
// update license status
$license_data = $response;
return $license_data;
}
/**
* Set the license status
*
* @param string $license_status
*/
public function set_license_status( $license_status ) {
$this->set_option( 'status', $license_status );
}
/**
* Get the license status
*
* @return string $license_status;
*/
public function get_license_status() {
$license_status = $this->get_option( 'status' );
return trim( $license_status );
}
/**
* Set the license key
*
* @param string $license_key
*/
public function set_license_key( $license_key ) {
$this->set_option( 'key', $license_key );
}
/**
* Gets the license key from constant or option
*
* @return string $license_key
*/
public function get_license_key() {
$license_key = $this->get_option( 'key' );
return trim( $license_key );
}
/**
* Gets the license expiry date
*
* @return string
*/
public function get_license_expiry_date() {
return $this->get_option( 'expiry_date');
}
/**
* Stores the license expiry date
*/
public function set_license_expiry_date( $expiry_date ) {
$this->set_option( 'expiry_date', $expiry_date );
}
/**
* Checks whether the license status is active
*
* @return boolean True if license is active
*/
public function license_is_valid() {
return ( $this->get_license_status() === 'valid' );
}
/**
* Get all license related options
*
* @return array Array of license options
*/
protected function get_options() {
// create option name
$option_name = $this->prefix . 'license';
// get array of options from db
if( $this->is_network_activated ) {
$options = get_site_option( $option_name, array( ) );
} else {
$options = get_option( $option_name, array( ) );
}
// setup array of defaults
$defaults = array(
'key' => '',
'status' => '',
'expiry_date' => ''
);
// merge options with defaults
$this->options = wp_parse_args( $options, $defaults );
return $this->options;
}
/**
* Set license related options
*
* @param array $options Array of new license options
*/
protected function set_options( array $options ) {
// create option name
$option_name = $this->prefix . 'license';
// update db
if( $this->is_network_activated ) {
update_site_option( $option_name, $options );
} else {
update_option( $option_name, $options );
}
}
/**
* Gets a license related option
*
* @param string $name The option name
* @return mixed The option value
*/
protected function get_option( $name ) {
$options = $this->get_options();
return $options[ $name ];
}
/**
* Set a license related option
*
* @param string $name The option name
* @param mixed $value The option value
*/
protected function set_option( $name, $value ) {
// get options
$options = $this->get_options();
// update option
$options[ $name ] = $value;
// save options
$this->set_options( $options );
}
public function show_license_form_heading() {
?>
<h3>
<?php printf( __( "%s: License Settings", $this->product->get_text_domain() ), $this->product->get_item_name() ); ?>&nbsp; &nbsp;
</h3>
<?php
}
/**
* Show a form where users can enter their license key
*
* @param boolean $embedded Boolean indicating whether this form is embedded in another form?
*/
public function show_license_form( $embedded = true ) {
$key_name = $this->prefix . 'license_key';
$nonce_name = $this->prefix . 'license_nonce';
$action_name = $this->prefix . 'license_action';
$visible_license_key = $this->get_license_key();
// obfuscate license key
$obfuscate = ( strlen( $this->get_license_key() ) > 5 && ( $this->license_is_valid() || ! $this->remote_license_activation_failed ) );
if($obfuscate) {
$visible_license_key = str_repeat('*', strlen( $this->get_license_key() ) - 4) . substr( $this->get_license_key(), -4 );
}
// make license key readonly when license key is valid or license is defined with a constant
$readonly = ( $this->license_is_valid() || $this->license_constant_is_defined );
require dirname( __FILE__ ) . '/views/form.php';
// enqueue script in the footer
add_action( 'admin_footer', array( $this, 'output_script'), 99 );
}
/**
* Check if the license form has been submitted
*/
public function catch_post_request() {
$name = $this->prefix . 'license_key';
// check if license key was posted and not empty
if( ! isset( $_POST[$name] ) ) {
return;
}
// run a quick security check
$nonce_name = $this->prefix . 'license_nonce';
if ( ! check_admin_referer( $nonce_name, $nonce_name ) ) {
return;
}
// @TODO: check for user cap?
// get key from posted value
$license_key = $_POST[$name];
// check if license key doesn't accidentally contain asterisks
if( strstr($license_key, '*') === false ) {
// sanitize key
$license_key = trim( sanitize_key( $_POST[$name] ) );
// save license key
$this->set_license_key( $license_key );
}
// does user have an activated valid license
if( ! $this->license_is_valid() ) {
// try to auto-activate license
return $this->activate_license();
}
$action_name = $this->prefix . 'license_action';
// was one of the action buttons clicked?
if( isset( $_POST[ $action_name ] ) ) {
$action = trim( $_POST[ $action_name ] );
switch($action) {
case 'activate':
return $this->activate_license();
break;
case 'deactivate':
return $this->deactivate_license();
break;
}
}
}
/**
* Output the script containing the YoastLicenseManager JS Object
*
* This takes care of disabling the 'activate' and 'deactivate' buttons
*/
public function output_script() {
require_once dirname( __FILE__ ) . '/views/script.php';
}
/**
* Set the constant used to define the license
*
* @param string $license_constant_name The license constant name
*/
public function set_license_constant_name( $license_constant_name ) {
$this->license_constant_name = trim( $license_constant_name );
$this->maybe_set_license_key_from_constant();
}
/**
* Maybe set license key from a defined constant
*/
private function maybe_set_license_key_from_constant( ) {
if( empty( $this->license_constant_name ) ) {
// generate license constant name
$this->set_license_constant_name( strtoupper( str_replace( array(' ', '-' ), '', sanitize_key( $this->product->get_item_name() ) ) ) . '_LICENSE');
}
// set license key from constant
if( defined( $this->license_constant_name ) ) {
$license_constant_value = constant( $this->license_constant_name );
// update license key value with value of constant
if( $this->get_license_key() !== $license_constant_value ) {
$this->set_license_key( $license_constant_value );
}
$this->license_constant_is_defined = true;
}
}
}
}
@@ -1,90 +0,0 @@
<?php
if ( class_exists( 'Yoast_License_Manager' ) && ! class_exists( "Yoast_Plugin_License_Manager", false ) ) {
class Yoast_Plugin_License_Manager extends Yoast_License_Manager {
/**
* Constructor
*
* @param Yoast_Product $product
*/
public function __construct( Yoast_Product $product ) {
parent::__construct( $product );
// Check if plugin is network activated. We should use site(wide) options in that case.
if( is_admin() && is_multisite() ) {
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
$this->is_network_activated = is_plugin_active_for_network( $product->get_slug() );
}
}
/**
* Setup auto updater for plugins
*/
public function setup_auto_updater() {
if ( $this->license_is_valid() ) {
// setup auto updater
require_once( dirname( __FILE__ ) . '/class-update-manager.php' );
require_once( dirname( __FILE__ ) . '/class-plugin-update-manager.php' );
new Yoast_Plugin_Update_Manager( $this->product, $this );
}
}
/**
* Setup hooks
*/
public function specific_hooks() {
// deactivate the license remotely on plugin deactivation
register_deactivation_hook( $this->product->get_slug(), array( $this, 'deactivate_license' ) );
}
/**
* Show a form where users can enter their license key
* Takes Multisites into account
*
* @param bool $embedded
* @return null
*/
public function show_license_form( $embedded = true ) {
// For non-multisites, always show the license form
if( ! is_multisite() ) {
parent::show_license_form( $embedded );
return;
}
// Plugin is network activated
if( $this->is_network_activated ) {
// We're on the network admin
if( is_network_admin() ) {
parent::show_license_form( $embedded );
} else {
// We're not in the network admin area, show a notice
parent::show_license_form_heading();
if ( is_super_admin() ) {
echo "<p>" . sprintf( __( '%s is network activated, you can manage your license in the <a href="%s">network admin license page</a>.', $this->product->get_text_domain() ), $this->product->get_item_name(), $this->product->get_license_page_url() ) . "</p>";
} else {
echo "<p>" . sprintf( __( '%s is network activated, please contact your site administrator to manage the license.', $this->product->get_text_domain() ), $this->product->get_item_name() ) . "</p>";
}
}
} else {
if( false == is_network_admin() ) {
parent::show_license_form( $embedded );
}
}
}
}
}
@@ -1,102 +0,0 @@
<?php
//set_site_transient( 'update_plugins', null );
if( class_exists( 'Yoast_Update_Manager' ) && ! class_exists( "Yoast_Plugin_Update_Manager", false ) ) {
class Yoast_Plugin_Update_Manager extends Yoast_Update_Manager {
/**
* Constructor
*
* @param string $api_url
* @param string $item_name
* @param string $license_key
* @param string $slug The path to the main plugin file, relative to plugins dir
* @param string $version
* @param string $author (optional)
* @param string $text_domain
*/
public function __construct( Yoast_Product $product, $license_key ) {
parent::__construct( $product, $license_key );
// setup hooks
$this->setup_hooks();
}
/**
* Setup hooks
*/
private function setup_hooks() {
// check for updates
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'set_updates_available_data' ) );
// get correct plugin information (when viewing details)
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
}
/**
* Check for updates and if so, add to "updates available" data
*
* @param object $data
* @return object $data
*/
public function set_updates_available_data( $data ) {
if ( empty( $data ) ) {
return $data;
}
// send of API request to check for updates
$remote_data = $this->get_remote_data();
// did we get a response?
if( $remote_data === false ) {
return $data;
}
// compare local version with remote version
if ( version_compare( $this->product->get_version(), $remote_data->new_version, '<' ) ) {
// remote version is newer, add to data
$data->response[ $this->product->get_slug() ] = $remote_data;
}
return $data;
}
/**
* Gets new plugin version details (view version x.x.x details)
*
* @uses api_request()
*
* @param object $data
* @param string $action
* @param object $args (optional)
*
* @return object $data
*/
public function plugins_api_filter( $data, $action = '', $args = null ) {
// only do something if we're checking for our plugin
if ( $action !== 'plugin_information' || ! isset( $args->slug ) || $args->slug !== $this->product->get_slug() ) {
return $data;
}
$api_response = $this->get_remote_data();
// did we get a response?
if ( $api_response === false ) {
return $data;
}
// return api response
return $api_response;
}
}
}
@@ -1,228 +0,0 @@
<?php
if( ! class_exists( "Yoast_Product", false ) ) {
/**
* Class Yoast_Product
*
* @todo create a license class and store an object of it in this class
*/
class Yoast_Product {
/**
* @var string The URL of the shop running the EDD API.
*/
protected $api_url;
/**
* @var string The item name in the EDD shop.
*/
protected $item_name;
/**
* @var string The theme slug or plugin file
*/
protected $slug;
/**
* @var string The version number of the item
*/
protected $version;
/**
* @var string The absolute url on which users can purchase a license
*/
protected $item_url;
/**
* @var string Absolute admin URL on which users can enter their license key.
*/
protected $license_page_url;
/**
* @var string The text domain used for translating strings
*/
protected $text_domain;
/**
* @var string The item author
*/
protected $author;
public function __construct( $api_url, $item_name, $slug, $version, $item_url = '', $license_page_url = '#', $text_domain = 'yoast', $author = 'Yoast' ) {
$this->api_url = $api_url;
$this->item_name = $item_name;
$this->slug = $slug;
$this->version = $version;
$this->item_url = $item_url;
$this->license_page_url = admin_url( $license_page_url );
$this->text_domain = $text_domain;
$this->author = $author;
// Fix possible empty item url
if ( $this->item_url === '' ) {
$this->item_url = $this->api_url;
}
if( is_admin() && is_multisite() ) {
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
if( is_plugin_active_for_network( $slug ) ) {
$this->license_page_url = network_admin_url( $license_page_url );
}
}
}
/**
* @param string $api_url
*/
public function set_api_url( $api_url ) {
$this->api_url = $api_url;
}
/**
* @return string
*/
public function get_api_url() {
return $this->api_url;
}
/**
* @param string $author
*/
public function set_author( $author ) {
$this->author = $author;
}
/**
* @return string
*/
public function get_author() {
return $this->author;
}
/**
* @param string $item_name
*/
public function set_item_name( $item_name ) {
$this->item_name = $item_name;
}
/**
* @return string
*/
public function get_item_name() {
return $this->item_name;
}
/**
* @param string $item_url
*/
public function set_item_url( $item_url ) {
$this->item_url = $item_url;
}
/**
* @return string
*/
public function get_item_url() {
return $this->item_url;
}
/**
* @param string $license_page_url
*/
public function set_license_page_url( $license_page_url ) {
$this->license_page_url = admin_page( $license_page_url );
}
/**
* @return string
*/
public function get_license_page_url() {
return $this->license_page_url;
}
/**
* @param string $slug
*/
public function set_slug( $slug ) {
$this->slug = $slug;
}
/**
* @return string
*/
public function get_slug() {
return $this->slug;
}
/**
* Returns the dirname of the slug and limits it to 15 chars
*
* @return string
*/
public function get_transient_prefix() {
return substr( dirname( $this->slug ), 0, 15 );
}
/**
* @param string $text_domain
*/
public function set_text_domain( $text_domain ) {
$this->text_domain = $text_domain;
}
/**
* @return string
*/
public function get_text_domain() {
return $this->text_domain;
}
/**
* @param string $version
*/
public function set_version( $version ) {
$this->version = $version;
}
/**
* @return string
*/
public function get_version() {
return $this->version;
}
/**
* Gets a Google Analytics Campaign url for this product
*
* @param string $link_identifier
* @return string The full URL
*/
public function get_tracking_url( $link_identifier = '' ) {
$tracking_vars = array(
'utm_campaign' => $this->get_item_name() . ' licensing',
'utm_medium' => 'link',
'utm_source' => $this->get_item_name(),
'utm_content' => $link_identifier
);
// url encode tracking vars
$tracking_vars = urlencode_deep( $tracking_vars );
$query_string = build_query( $tracking_vars );
return $this->get_item_url() . '#' . $query_string;
}
}
}
@@ -1,53 +0,0 @@
<?php
if( class_exists( 'Yoast_License_Manager' ) && ! class_exists( "Yoast_Theme_License_Manager", false ) ) {
class Yoast_Theme_License_Manager extends Yoast_License_Manager {
/**
* Setup auto updater for themes
*/
public function setup_auto_updater() {
if ( $this->license_is_valid() ) {
// setup auto updater
require_once dirname( __FILE__ ) . '/class-update-manager.php';
require_once dirname( __FILE__ ) . '/class-theme-update-manager.php'; // @TODO: Autoload?
new Yoast_Theme_Update_Manager( $this->product, $this );
}
}
/**
* Setup hooks
*/
public function specific_hooks() {
// remotely deactivate license upon switching away from this theme
add_action( 'switch_theme', array( $this, 'deactivate_license' ) );
// Add the license menu
add_action( 'admin_menu', array( $this, 'add_license_menu' ) );
}
/**
* Add license page and add it to Themes menu
*/
public function add_license_menu() {
$theme_page = add_theme_page( sprintf( __( '%s License', $this->product->get_text_domain() ), $this->product->get_item_name() ), __( 'Theme License', $this->product->get_text_domain() ), 'manage_options', 'theme-license', array( $this, 'show_license_page' ) );
}
/**
* Shows license page
*/
public function show_license_page() {
?>
<div class="wrap">
<?php settings_errors(); ?>
<?php $this->show_license_form( false ); ?>
</div>
<?php
}
}
}
@@ -1,149 +0,0 @@
<?php
if( class_exists( 'Yoast_Update_Manager' ) && ! class_exists( "Yoast_Theme_Update_Manager", false ) ) {
class Yoast_Theme_Update_Manager extends Yoast_Update_Manager {
/**
* Constructor
*
* @param string $api_url
* @param string $item_name
* @param string $license_key
* @param string $slug
* @param string $theme_version
* @param string $author (optional)
*/
public function __construct( Yoast_Product $product, $license_key ) {
parent::__construct( $product, $license_key );
// setup hooks
$this->setup_hooks();
}
/**
* Get the current theme version
*
* @return string The version number
*/
private function get_theme_version() {
// if version was not set, get it from the Theme stylesheet
if( $this->product->get_version() === '' ) {
$theme = wp_get_theme( $this->product->get_slug() );
return $theme->get( 'Version' );
}
return $this->product->get_version();
}
/**
* Setup hooks
*/
private function setup_hooks() {
add_filter( 'site_transient_update_themes', array( $this, 'set_theme_update_transient' ) );
add_action( 'load-themes.php', array( $this, 'load_themes_screen' ) );
}
/**
* Set "updates available" transient
*/
public function set_theme_update_transient( $value ) {
$update_data = $this->get_update_data();
if( $update_data === false ) {
return $value;
}
// add update data to "updates available" array. convert object to array.
$value->response[ $this->product->get_slug() ] = (array) $update_data;
return $value;
}
/**
* Add hooks and scripts to the Appearance > Themes screen
*/
public function load_themes_screen() {
$update_data = $this->get_update_data();
// only do if an update is available
if( $update_data === false ) {
return;
}
add_thickbox();
add_action( 'admin_notices', array( $this, 'show_update_details' ) );
}
/**
* Show update link.
* Opens Thickbox with Changelog.
*/
public function show_update_details() {
$update_data = $this->get_update_data();
// only show if an update is available
if( $update_data === false ) {
return;
}
$update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
$update_onclick = ' onclick="if ( confirm(\'' . esc_js( __( "Updating this theme will lose any customizations you have made. 'Cancel' to stop, 'OK' to update." ) ) . '\') ) {return true;}return false;"';
?>
<div id="update-nag">
<?php
printf(
__( '<strong>%s version %s</strong> is available. <a href="%s" class="thickbox" title="%s">Check out what\'s new</a> or <a href="%s" %s>update now</a>.' ),
$this->product->get_item_name(),
$update_data->new_version,
'#TB_inline?width=640&amp;inlineId=' . $this->product->get_slug() . '_changelog',
$this->get_item_name(),
$update_url,
$update_onclick
);
?>
</div>
<div id="<?php echo $this->product->get_slug(); ?>_changelog" style="display: none;">
<?php echo wpautop( $update_data->sections['changelog'] ); ?>
</div>
<?php
}
/**
* Get update data
*
* This gets the update data from a transient (12 hours), if set.
* If not, it will make a remote request and get the update data.
*
* @return object $update_data Object containing the update data
*/
public function get_update_data() {
$api_response = $this->get_remote_data();
if( false === $api_response ) {
return false;
}
$update_data = $api_response;
// check if a new version is available.
if ( version_compare( $this->get_theme_version(), $update_data->new_version, '>=' ) ) {
return false;
}
// an update is available
return $update_data;
}
}
}
@@ -1,211 +0,0 @@
<?php
if( ! class_exists( "Yoast_Update_Manager", false ) ) {
class Yoast_Update_Manager {
/**
* @var Yoast_Product
*/
protected $product;
/**
* @var Yoast_License_Manager
*/
protected $license_manager;
/**
* @var string
*/
protected $error_message = '';
/**
* @var object
*/
protected $update_response = null;
/**
* @var string The transient name storing the API response
*/
private $response_transient_key = '';
/**
* @var string The transient name that stores failed request tries
*/
private $request_failed_transient_key = '';
/**
* Constructor
*
* @param string $api_url The url to the EDD shop
* @param string $item_name The item name in the EDD shop
* @param string $license_key The (valid) license key
* @param string $slug The slug. This is either the plugin main file path or the theme slug.
* @param string $version The current plugin or theme version
* @param string $author (optional) The item author.
*/
public function __construct( Yoast_Product $product, $license_manager ) {
$this->product = $product;
$this->license_manager = $license_manager;
// generate transient names
$this->response_transient_key = $this->product->get_transient_prefix() . '-update-response';
$this->request_failed_transient_key = $this->product->get_transient_prefix() . '-update-request-failed';
// maybe delete transient
$this->maybe_delete_transients();
}
/**
* Deletes the various transients
* If we're on the update-core.php?force-check=1 page
*/
private function maybe_delete_transients() {
global $pagenow;
if( $pagenow === 'update-core.php' && isset( $_GET['force-check'] ) ) {
delete_transient( $this->response_transient_key );
delete_transient( $this->request_failed_transient_key );
}
}
/**
* If the update check returned a WP_Error, show it to the user
*/
public function show_update_error() {
if ( $this->error_message === '' ) {
return;
}
?>
<div class="error">
<p><?php printf( __( '%s failed to check for updates because of the following error: <em>%s</em>', $this->product->get_text_domain() ), $this->product->get_item_name(), $this->error_message ); ?></p>
</div>
<?php
}
/**
* Calls the API and, if successfull, returns the object delivered by the API.
*
* @uses get_bloginfo()
* @uses wp_remote_post()
* @uses is_wp_error()
*
* @return false||object
*/
private function call_remote_api() {
// only check if the failed transient is not set (or if it's expired)
if( get_transient( $this->request_failed_transient_key ) !== false ) {
return false;
}
// start request process
global $wp_version;
// set a transient to prevent failed update checks on every page load
// this transient will be removed if a request succeeds
set_transient( $this->request_failed_transient_key, 'failed', 10800 );
// setup api parameters
$api_params = array(
'edd_action' => 'get_version',
'license' => $this->license_manager->get_license_key(),
'item_name' => $this->product->get_item_name(),
'wp_version' => $wp_version,
'item_version' => $this->product->get_version(),
'url' => home_url(),
'slug' => $this->product->get_slug()
);
// setup request parameters
$request_params = array(
'method' => 'POST',
'body' => $api_params
);
require_once dirname( __FILE__ ) . '/class-api-request.php';
$request = new Yoast_API_Request( $this->product->get_api_url(), $request_params );
if( $request->is_valid() !== true ) {
// show error message
$this->error_message = $request->get_error_message();
add_action( 'admin_notices', array( $this, 'show_update_error' ) );
return false;
}
// request succeeded, delete transient indicating a request failed
delete_transient( $this->request_failed_transient_key );
// decode response
$response = $request->get_response();
// check if response returned that a given site was inactive
if( isset( $response->license_check ) && ! empty( $response->license_check ) && $response->license_check != 'valid' ) {
// deactivate local license
$this->license_manager->set_license_status( 'invalid' );
// show notice to let the user know we deactivated his/her license
$this->error_message = __( "This site has not been activated properly on yoast.com and thus cannot check for future updates. Please activate your site with a valid license key.", $this->product->get_text_domain() );
add_action( 'admin_notices', array( $this, 'show_update_error' ) );
}
$response->sections = maybe_unserialize( $response->sections );
// store response
set_transient( $this->response_transient_key, $response, 10800 );
return $response;
}
/**
* Gets the remote product data (from the EDD API)
*
* - If it was previously fetched in the current requests, this gets it from the instance property
* - Next, it tries the 3-hour transient
* - Next, it calls the remote API and stores the result
*
* @return object
*/
protected function get_remote_data() {
// always use property if it's set
if( null !== $this->update_response ) {
return $this->update_response;
}
// get cached remote data
$data = $this->get_cached_remote_data();
// if cache is empty or expired, call remote api
if( $data === false ) {
$data = $this->call_remote_api();
}
$this->update_response = $data;
return $data;
}
/**
* Gets the remote product data from a 3-hour transient
*
* @return bool|mixed
*/
private function get_cached_remote_data() {
$data = get_transient( $this->response_transient_key );
if( $data ) {
return $data;
}
return false;
}
}
}
@@ -1,2 +0,0 @@
<?php
//Nothing to see here
@@ -1,2 +0,0 @@
<?php
//Nothing to see here
@@ -1,74 +0,0 @@
<?php
/*
Plugin Name: Sample Plugin
Version: 1.0
Plugin URI: https://yoast.com/
Description: A sample plugin to test the License Manager
Author: Yoast, DvanKooten
Author URI: http://yoast.com/
Text Domain: sample-plugin
*/
/**
* Class Sample_Plugin
*
*/
class Sample_Plugin {
public function __construct() {
// we only need license stuff inside the admin area
if ( is_admin() ) {
// add menu item
add_action( 'admin_menu', array( $this, 'add_license_menu' ) );
// load license class
$this->load_license_manager();
}
}
/**
* Loads the License_Plugin_Manager class
*
* The class will take care of the rest: notices, license (de)activations, updates, etc..
*/
public function load_license_manager() {
// Instantiate license class
$license_manager = new Yoast_Plugin_License_Manager( new Sample_Product() );
// Setup the required hooks
$license_manager->setup_hooks();
}
/**
* Add license page and add it to Themes menu
*/
public function add_license_menu() {
$theme_page = add_options_page( sprintf( __( '%s License', $this->text_domain ), $this->item_name ), sprintf( __( '%s License', $this->text_domain ), $this->item_name ), 'manage_options', $this->text_domain . '-license', array( $this, 'show_license_page' ) );
}
/**
* Shows license page
*/
public function show_license_page() {
// Instantiate license class
$license_manager = new Yoast_Plugin_License_Manager( new Sample_Product() );
?>
<div class="wrap">
<?php //settings_errors(); ?>
<?php $license_manager->show_license_form( false ); ?>
</div>
<?php
}
}
new Sample_Plugin();
@@ -1,23 +0,0 @@
<?php
/**
* Class Sample_Product
*
* Our sample product class
*/
class Sample_Product extends Yoast_Product {
public function __construct() {
parent::__construct(
'https://yoast.com',
'Sample Product',
'sample-product',
'1.0',
'https://yoast.com/wordpress/plugins/sample-product/',
'admin.php?page=sample-product',
'sample-product',
'Yoast'
);
}
}
@@ -1,11 +0,0 @@
<?php
if( is_admin() ) {
// Instantiate license class
$license_manager = new Yoast_Theme_License_Manager( new Sample_Product() );
// Setup the required hooks
$license_manager->setup_hooks();
}
@@ -1,94 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
header( 'HTTP/1.0 403 Forbidden' );
die;
}
/**
* @var Yoast_Product $product
*/
$product = $this->product;
$this->show_license_form_heading();
// Output form tags if we're not embedded in another form
if( ! $embedded ) {
echo '<form method="post" action="">';
}
wp_nonce_field( $nonce_name, $nonce_name ); ?>
<table class="form-table yoast-license-form">
<tbody>
<tr valign="top">
<th scope="row" valign="top"><?php _e( 'License status', $product->get_text_domain() ); ?></th>
<td>
<?php if( $this->license_is_valid() ) { ?>
<span style="color: white; background: limegreen; padding:3px 6px;">ACTIVE</span> &nbsp; - &nbsp; you are receiving updates.
<?php } else { ?>
<span style="color:white; background: red; padding: 3px 6px;">INACTIVE</span> &nbsp; - &nbsp; you are <strong>not</strong> receiving updates.
<?php } ?>
</td>
</tr>
<tr valign="top">
<th scope="row" valign="top"><?php _e('Toggle license status', $product->get_text_domain() ); ?></th>
<td class="yoast-license-toggler">
<?php if( $this->license_is_valid() ) { ?>
<button name="<?php echo esc_attr( $action_name ); ?>" type="submit" class="button-secondary yoast-license-deactivate" value="deactivate"><?php echo esc_html_e( 'Deactivate License', $product->get_text_domain() ); ?></button> &nbsp;
<small><?php _e( '(deactivate your license so you can activate it on another WordPress site)', $product->get_text_domain() ); ?></small>
<?php } else {
if( $this->get_license_key() !== '') { ?>
<button name="<?php echo esc_attr( $action_name ); ?>" type="submit" class="button-secondary yoast-license-activate" value="activate" /><?php echo esc_html_e('Activate License', $product->get_text_domain() ); ?></button> &nbsp;
<?php } else {
_e( 'Please enter a license key in the field below first.', $product->get_text_domain() );
}
} ?>
</td>
</tr>
<tr valign="top">
<th scope="row" valign="top"><?php _e( 'License Key', $product->get_text_domain() ); ?></th>
<td>
<input name="<?php echo esc_attr( $key_name ); ?>" type="text" class="regular-text yoast-license-key-field <?php if( $obfuscate ) { ?>yoast-license-obfuscate<?php } ?>" value="<?php echo esc_attr( $visible_license_key ); ?>" placeholder="<?php echo esc_attr( sprintf( __( 'Paste your %s license key here..', $product->get_text_domain() ), $product->get_item_name() ) ); ?>" <?php if( $readonly ) { echo 'readonly="readonly"'; } ?> />
<?php if( $this->license_constant_is_defined ) { ?>
<p class="help"><?php printf( __( "You defined your license key using the %s PHP constant.", $product->get_text_domain() ), '<code>' . $this->license_constant_name . '</code>' ); ?></p>
<?php } ?>
</td>
</tr>
</tbody>
</table>
<?php
if( $this->license_is_valid() ) {
$expiry_date = strtotime( $this->get_license_expiry_date() );
if( $expiry_date !== false ) {
echo '<p>';
printf( __( 'Your %s license will expire on %s.', $product->get_text_domain() ), $product->get_item_name(), date('F jS Y', $expiry_date ) );
if( strtotime( '+3 months' ) > $expiry_date ) {
printf( ' ' . __('%sRenew your license now%s.', $product->get_text_domain() ), '<a href="'. $this->product->get_tracking_url( 'renewal' ) .'">', '</a>' );
}
echo '</p>';
}
}
// Only show a "Save Changes" button and end form if we're not embedded in another form.
if( ! $embedded ) {
// only show "Save Changes" button if license is not activated and not defined with a constant
if( $readonly === false ) {
submit_button();
}
echo '</form>';
}
$product = null;
@@ -1,2 +0,0 @@
<?php
//Nothing to see here
@@ -1,67 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
header( 'HTTP/1.0 403 Forbidden' );
die;
}
?><script type="text/javascript">
(function($) {
if( typeof YoastLicenseManager !== "undefined" ) {
return;
}
window.YoastLicenseManager = (function () {
function init() {
var $keyInputs = $(".yoast-license-key-field.yoast-license-obfuscate");
var $actionButtons = $('.yoast-license-toggler button');
var $submitButtons = $('input[type="submit"], button[type="submit"]');
$submitButtons.click( addDisableEvent );
$actionButtons.click( actOnLicense );
$keyInputs.click( setEmptyValue );
}
function setEmptyValue() {
if( ! $(this).is('[readonly]') ) {
$(this).val('');
}
}
function actOnLicense() {
var $formScope = $(this).closest('form');
var $actionButton = $formScope.find('.yoast-license-toggler button');
// fake input field with exact same name => value
$("<input />")
.attr('type', 'hidden')
.attr( 'name', $(this).attr('name') )
.val( $(this).val() )
.appendTo( $formScope );
// change button text to show we're working..
var text = ( $actionButton.hasClass('yoast-license-activate') ) ? "Activating..." : "Deactivating...";
$actionButton.text( text );
}
function addDisableEvent() {
var $formScope = $(this).closest('form');
$formScope.submit(disableButtons);
}
function disableButtons() {
var $formScope = $(this).closest('form');
var $submitButton = $formScope.find('input[type="submit"], button[type="submit"]');
$submitButton.prop( 'disabled', true );
}
return {
init: init
}
})();
YoastLicenseManager.init();
})(jQuery);
</script>
@@ -0,0 +1,52 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$active_tab = filter_input( INPUT_GET, 'tab' );
$tabs = array(
'breadcrumbs' => array(
'label' => __( 'Breadcrumbs', 'wordpress-seo' ),
'opt_group' => 'wpseo_internallinks',
),
'permalinks' => array(
'label' => __( 'Permalinks', 'wordpress-seo' ),
'opt_group' => 'wpseo_permalinks',
),
'rss' => array(
'label' => __( 'RSS', 'wordpress-seo' ),
'opt_group' => 'wpseo_rss',
),
);
if ( '' === $active_tab || ! in_array( $active_tab, array_keys( $tabs ) ) ) {
$active_tab = 'breadcrumbs';
}
Yoast_Form::get_instance()->admin_header( true, $tabs[ $active_tab ]['opt_group'] );
?>
<h2 class="nav-tab-wrapper">
<?php
foreach ( $tabs as $tab_key => $tab_opt ) {
$active = '';
if ( $active_tab == $tab_key ) {
$active = ' nav-tab-active';
}
echo '<a class="nav-tab' . $active . '" id="' . $tab_key . '-tab" href="' . admin_url( 'admin.php?page=wpseo_advanced&tab=' . $tab_key ) . '">' . $tab_opt['label'] . '</a>';
}
?>
</h2>
<br/>
<?php
require_once WPSEO_PATH . 'admin/views/tab-' . $active_tab . '.php';
Yoast_Form::get_instance()->admin_footer();
@@ -1,8 +1,6 @@
<?php
/**
*
*
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -11,18 +9,15 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
if ( filter_input( INPUT_GET, 'intro' ) ) {
require WPSEO_PATH . 'admin/views/about.php';
return;
}
$options = get_option( 'wpseo' );
if ( isset( $_GET['allow_tracking'] ) && check_admin_referer( 'wpseo_activate_tracking', 'nonce' ) ) {
$options['tracking_popup_done'] = true;
if ( $_GET['allow_tracking'] == 'yes' ) {
$options['yoast_tracking'] = true;
}
else {
$options['yoast_tracking'] = false;
}
$options['yoast_tracking'] = ( $_GET['allow_tracking'] == 'yes' );
update_option( 'wpseo', $options );
if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
@@ -61,7 +56,7 @@ if ( isset( $_GET['fixmetadesc'] ) && check_admin_referer( 'wpseo-fix-metadesc',
$header_file = fopen( $path . '/header.php', 'w+' );
if ( $header_file ) {
if ( fwrite( $header_file, $fcontent ) !== false ) {
$msg .= __( 'Removed hardcoded meta description.', 'wordpress-seo' );
$msg .= __( 'Removed hardcoded meta description.', 'wordpress-seo' );
$options['theme_has_description'] = false;
$options['theme_description_found'] = '';
update_option( 'wpseo', $options );
@@ -98,75 +93,147 @@ if ( isset( $_GET['checkmetadesc'] ) ) {
$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'nonce', 'checkmetadesc' ), $_SERVER['REQUEST_URI'] );
}
}
$yform = Yoast_Form::get_instance();
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo' ), 'wpseo' );
$yform->admin_header( true, 'wpseo' );
do_action( 'wpseo_all_admin_notices' );
if ( is_array( $options['blocking_files'] ) && count( $options['blocking_files'] ) > 0 ) {
echo '<p id="blocking_files" class="wrong">'
. '<a href="javascript:wpseo_killBlockingFiles(\'' . esc_js( wp_create_nonce( 'wpseo-blocking-files' ) ) . '\')" class="button fixit">' . __( 'Fix it.', 'wordpress-seo' ) . '</a>'
. __( 'The following file(s) is/are blocking your XML sitemaps from working properly:', 'wordpress-seo' ) . '<br />';
echo '<p id="blocking_files" class="wrong">';
echo '<a href="javascript:wpseo_killBlockingFiles(\'', esc_js( wp_create_nonce( 'wpseo-blocking-files' ) ), '\')" class="button fixit">', __( 'Fix it.', 'wordpress-seo' ), '</a>';
echo __( 'The following file(s) is/are blocking your XML sitemaps from working properly:', 'wordpress-seo' ), '<br />';
foreach ( $options['blocking_files'] as $file ) {
echo esc_html( $file ) . '<br/>';
echo esc_html( $file ), '<br/>';
}
echo __( 'Either delete them (this can be done with the "Fix it" button) or disable WP SEO XML sitemaps.', 'wordpress-seo' );
echo '</p>';
unset( $file );
echo '
', __( 'Either delete them (this can be done with the "Fix it" button) or disable WP SEO XML sitemaps.', 'wordpress-seo' ), '
</p>';
}
if ( $options['theme_description_found'] !== '' ) {
echo '<p id="metadesc_found notice" class="wrong settings_error">'
. '<a href="' . esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo-fix-metadesc' ) ), admin_url( 'admin.php?page=wpseo_dashboard&fixmetadesc' ) ) ) . '" class="button fixit">' . __( 'Fix it.', 'wordpress-seo' ) . '</a>'
. ' <a href="' . esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo-check-metadesc' ) ), admin_url( 'admin.php?page=wpseo_dashboard&checkmetadesc' ) ) ) . '" class="button checkit">' . __( 'Re-check theme.', 'wordpress-seo' ) . '</a>'
. __( 'Your theme contains a meta description, which blocks WordPress SEO from working properly, please delete the following line, or press fix it:', 'wordpress-seo' ) . '<br />';
echo '<code>' . esc_html( $options['theme_description_found'] ) . '</code>';
echo '<p id="metadesc_found notice" class="wrong settings_error">';
echo '<a href="', esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo-fix-metadesc' ) ), admin_url( 'admin.php?page=wpseo_dashboard&fixmetadesc' ) ) ), '" class="button fixit">', __( 'Fix it.', 'wordpress-seo' ), '</a>';
echo ' <a href="', esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo-check-metadesc' ) ), admin_url( 'admin.php?page=wpseo_dashboard&checkmetadesc' ) ) ), '" class="button checkit">', __( 'Re-check theme.', 'wordpress-seo' ), '</a>';
echo __( 'Your theme contains a meta description, which blocks WordPress SEO from working properly, please delete the following line, or press fix it:', 'wordpress-seo' ), '<br />';
echo '<code>', esc_html( $options['theme_description_found'] ), '</code>';
echo '</p>';
}
if ( strpos( get_option( 'permalink_structure' ), '%postname%' ) === false && $options['ignore_permalink'] === false ) {
echo '<p id="wrong_permalink" class="wrong">'
. '<a href="' . esc_url( admin_url( 'options-permalink.php' ) ) . '" class="button fixit">' . __( 'Fix it.', 'wordpress-seo' ) . '</a>'
. '<a href="javascript:wpseo_setIgnore(\'permalink\',\'wrong_permalink\',\'' . esc_js( wp_create_nonce( 'wpseo-ignore' ) ) . '\');" class="button fixit">' . __( 'Ignore.', 'wordpress-seo' ) . '</a>'
. __( 'You do not have your postname in the URL of your posts and pages, it is highly recommended that you do. Consider setting your permalink structure to <strong>/%postname%/</strong>.', 'wordpress-seo' ) . '</p>';
echo '<p id="wrong_permalink" class="wrong">';
echo '<a href="', esc_url( admin_url( 'options-permalink.php' ) ), '" class="button fixit">', __( 'Fix it.', 'wordpress-seo' ), '</a>';
echo '<a href="javascript:wpseo_setIgnore(\'permalink\',\'wrong_permalink\',\'', esc_js( wp_create_nonce( 'wpseo-ignore' ) ), '\');" class="button fixit">', __( 'Ignore.', 'wordpress-seo' ), '</a>';
echo __( 'You do not have your postname in the URL of your posts and pages, it is highly recommended that you do. Consider setting your permalink structure to <strong>/%postname%/</strong>.', 'wordpress-seo' ), '</p>';
}
if ( get_option( 'page_comments' ) && $options['ignore_page_comments'] === false ) {
echo '<p id="wrong_page_comments" class="wrong">'
. '<a href="javascript:setWPOption(\'page_comments\',\'0\',\'wrong_page_comments\',\'' . esc_js( wp_create_nonce( 'wpseo-setoption' ) ) . '\');" class="button fixit">' . __( 'Fix it.', 'wordpress-seo' ) . '</a>'
. '<a href="javascript:wpseo_setIgnore(\'page_comments\',\'wrong_page_comments\',\'' . esc_js( wp_create_nonce( 'wpseo-ignore' ) ) . '\');" class="button fixit">' . __( 'Ignore.', 'wordpress-seo' ) . '</a>'
. __( 'Paging comments is enabled, this is not needed in 999 out of 1000 cases, so the suggestion is to disable it, to do that, simply uncheck the box before "Break comments into pages..."', 'wordpress-seo' ) . '</p>';
echo '<p id="wrong_page_comments" class="wrong">';
echo '<a href="javascript:setWPOption(\'page_comments\',\'0\',\'wrong_page_comments\',\'', esc_js( wp_create_nonce( 'wpseo-setoption' ) ), '\');" class="button fixit">', __( 'Fix it.', 'wordpress-seo' ), '</a>';
echo '<a href="javascript:wpseo_setIgnore(\'page_comments\',\'wrong_page_comments\',\'', esc_js( wp_create_nonce( 'wpseo-ignore' ) ), '\');" class="button fixit">', __( 'Ignore.', 'wordpress-seo' ), '</a>';
echo __( 'Paging comments is enabled, this is not needed in 999 out of 1000 cases, so the suggestion is to disable it, to do that, simply uncheck the box before "Break comments into pages..."', 'wordpress-seo' ), '</p>';
}
echo '<h2>' . __( 'General', 'wordpress-seo' ) . '</h2>';
?>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab nav-tab-active" id="general-tab"
href="#top#general"><?php _e( 'General', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="knowledge-graph-tab"
href="#top#knowledge-graph"><?php echo ( 'company' === $options['company_or_person'] ) ? __( 'Company Info', 'wordpress-seo' ) : __( 'Your Info', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="webmaster-tools-tab"
href="#top#webmaster-tools"><?php _e( 'Webmaster Tools', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="security-tab" href="#top#security"><?php _e( 'Security', 'wordpress-seo' ); ?></a>
</h2>
if ( $options['ignore_tour'] === true ) {
echo '<label class="select">' . __( 'Introduction Tour:', 'wordpress-seo' ) . '</label><a class="button-secondary" href="' . esc_url( admin_url( 'admin.php?page=wpseo_dashboard&wpseo_restart_tour' ) ) . '">' . __( 'Start Tour', 'wordpress-seo' ) . '</a>';
echo '<p class="desc label">' . __( 'Take this tour to quickly learn about the use of this plugin.', 'wordpress-seo' ) . '</p>';
}
<div id="general" class="wpseotab">
<p>
<strong><?php _e( 'Tracking', 'wordpress-seo' ); ?></strong><br/>
<?php _e( "To maintain a plugin as big as WordPress SEO, we need to know what we're dealing with: what kinds of other plugins our users are using, what themes, etc. Please allow us to track that data from your install. It will not track <em>any</em> user details, so your security and privacy are safe with us.", 'wordpress-seo' ); ?>
</p>
<?php $yform->checkbox( 'yoast_tracking', __( 'Allow tracking of this WordPress install\'s anonymous data.', 'wordpress-seo' ) ); ?>
echo '<label class="select">' . __( 'Default Settings:', 'wordpress-seo' ) . '</label><a onclick="if( !confirm(\'' . __( 'Are you sure you want to reset your SEO settings?', 'wordpress-seo' ) . '\') ) return false;" class="button-secondary" href="' . esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo_reset_defaults' ) ), admin_url( 'admin.php?page=wpseo_dashboard&wpseo_reset_defaults' ) ) ) . '">' . __( 'Reset Default Settings', 'wordpress-seo' ) . '</a>';
echo '<p class="desc label">' . __( 'If you want to restore a site to the default WordPress SEO settings, press this button.', 'wordpress-seo' ) . '</p>';
<br/>
echo '<h2>' . __( 'Tracking', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->checkbox( 'yoast_tracking', __( 'Allow tracking of this WordPress install\'s anonymous data.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( "To maintain a plugin as big as WordPress SEO, we need to know what we're dealing with: what kinds of other plugins our users are using, what themes, etc. Please allow us to track that data from your install. It will not track <em>any</em> user details, so your security and privacy are safe with us.", 'wordpress-seo' ) . '</p>';
<?php if ( $options['ignore_tour'] === true ) { ?>
<p>
<strong><?php _e( 'Introduction Tour', 'wordpress-seo' ); ?></strong><br/>
<?php _e( 'Take this tour to quickly learn about the use of this plugin.', 'wordpress-seo' ); ?>
</p>
<p>
<?php $yform->label( __( 'Introduction Tour:', 'wordpress-seo' ), array( 'class' => 'select' ) ); ?>
<a class="button-secondary"
href="<?php echo esc_url( admin_url( 'admin.php?page=wpseo_dashboard&wpseo_restart_tour=1' ) ); ?>"><?php _e( 'Start Tour', 'wordpress-seo' ); ?></a>
</p>
<?php } ?>
echo '<h2>' . __( 'Security', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->checkbox( 'disableadvanced_meta', __( 'Disable the Advanced part of the WordPress SEO meta box', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'Unchecking this box allows authors and editors to redirect posts, noindex them and do other things you might not want if you don\'t trust your authors.', 'wordpress-seo' ) . '</p>';
<br/>
echo '<h2>' . __( 'Webmaster Tools', 'wordpress-seo' ) . '</h2>';
echo '<p>' . __( 'You can use the boxes below to verify with the different Webmaster Tools, if your site is already verified, you can just forget about these. Enter the verify meta values for:', 'wordpress-seo' ) . '</p>';
echo $wpseo_admin_pages->textinput( 'alexaverify', '<a target="_blank" href="http://www.alexa.com/siteowners/claim">' . __( 'Alexa Verification ID', 'wordpress-seo' ) . '</a>' );
echo $wpseo_admin_pages->textinput( 'msverify', '<a target="_blank" href="' . esc_url( 'http://www.bing.com/webmaster/?rfp=1#/Dashboard/?url=' . urlencode( str_replace( 'http://', '', get_bloginfo( 'url' ) ) ) ) . '">' . __( 'Bing Webmaster Tools', 'wordpress-seo' ) . '</a>' );
echo $wpseo_admin_pages->textinput( 'googleverify', '<a target="_blank" href="' . esc_url( 'https://www.google.com/webmasters/verification/verification?hl=en&siteUrl=' . urlencode( get_bloginfo( 'url' ) ) . '/' ) . '">' . __( 'Google Webmaster Tools', 'wordpress-seo' ) . '</a>' );
echo $wpseo_admin_pages->textinput( 'pinterestverify', '<a target="_blank" href="https://help.pinterest.com/entries/22488487-Verify-with-HTML-meta-tags">' . __( 'Pinterest', 'wordpress-seo' ) . '</a>' );
echo $wpseo_admin_pages->textinput( 'yandexverify', '<a target="_blank" href="http://help.yandex.com/webmaster/service/rights.xml#how-to">' . __( 'Yandex Webmaster Tools', 'wordpress-seo' ) . '</a>' );
<p>
<strong><?php _e( 'Restore Default Settings', 'wordpress-seo' ); ?></strong><br/>
<?php _e( 'If you want to restore a site to the default WordPress SEO settings, press this button.', 'wordpress-seo' ); ?>
</p>
<p>
<?php $yform->label( __( 'Default Settings:', 'wordpress-seo' ), array( 'class' => 'select' ) ); ?>
<a onclick="if( !confirm('<?php _e( 'Are you sure you want to reset your SEO settings?', 'wordpress-seo' ); ?>') ) return false;" class="button" href="<?php echo esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'wpseo_reset_defaults' ) ), admin_url( 'admin.php?page=wpseo_dashboard&wpseo_reset_defaults=1' ) ) ); ?>"><?php _e( 'Reset Default Settings', 'wordpress-seo' ); ?></a>
</p>
</div>
<div id="knowledge-graph" class="wpseotab">
<h3><?php _e( 'Website name', 'wordpress-seo' ); ?></h3>
<p>
<?php
_e( 'Google shows your website\'s name in the search results, we will default to your site name but you can adapt it here. You can also provide an alternate website name you want Google to consider.', 'wordpress-seo' );
?>
</p>
<?php
$yform->textinput( 'website_name', __( 'Website name', 'wordpress-seo' ), array( 'placeholder' => get_bloginfo( 'name' ) ) );
$yform->textinput( 'alternate_website_name', __( 'Alternate name', 'wordpress-seo' ) );
?>
<h3><?php _e( 'Company or person', 'wordpress-seo' ); ?></h3>
<p>
<?php
// @todo add KB link - JdV
_e( 'This data is shown as metadata in your site. It is intended to appear in Google\'s Knowledge Graph. You can be either a company, or a person, choose either:', 'wordpress-seo' );
?>
</p>
<?php
$yform->select( 'company_or_person', __( 'Company or person', 'wordpress-seo' ), array(
'' => __( 'Choose whether you\'re a company or person', 'wordpress-seo' ),
'company' => __( 'Company', 'wordpress-seo' ),
'person' => __( 'Person', 'wordpress-seo' ),
) );
?>
<div id="knowledge-graph-company">
<h2><?php _e( 'Company', 'wordpress-seo' ); ?></h2>
<?php
$yform->textinput( 'company_name', __( 'Company Name', 'wordpress-seo' ) );
$yform->media_input( 'company_logo', __( 'Company Logo', 'wordpress-seo' ) );
?>
</div>
<div id="knowledge-graph-person">
<h2><?php _e( 'Person', 'wordpress-seo' ); ?></h2>
<?php $yform->textinput( 'person_name', __( 'Your name', 'wordpress-seo' ) ); ?>
</div>
</div>
<div id="webmaster-tools" class="wpseotab">
<?php
echo '<p>', __( 'You can use the boxes below to verify with the different Webmaster Tools, if your site is already verified, you can just forget about these. Enter the verify meta values for:', 'wordpress-seo' ), '</p>';
$yform->textinput( 'alexaverify', '<a target="_blank" href="http://www.alexa.com/siteowners/claim">' . __( 'Alexa Verification ID', 'wordpress-seo' ) . '</a>' );
$yform->textinput( 'msverify', '<a target="_blank" href="' . esc_url( 'http://www.bing.com/webmaster/?rfp=1#/Dashboard/?url=' . urlencode( str_replace( 'http://', '', get_bloginfo( 'url' ) ) ) ) . '">' . __( 'Bing Webmaster Tools', 'wordpress-seo' ) . '</a>' );
$yform->textinput( 'googleverify', '<a target="_blank" href="' . esc_url( 'https://www.google.com/webmasters/verification/verification?hl=en&siteUrl=' . urlencode( get_bloginfo( 'url' ) ) . '/' ) . '">' . __( 'Google Webmaster Tools', 'wordpress-seo' ) . '</a>' );
$yform->textinput( 'yandexverify', '<a target="_blank" href="http://help.yandex.com/webmaster/service/rights.xml#how-to">' . __( 'Yandex Webmaster Tools', 'wordpress-seo' ) . '</a>' );
?>
</div>
<div id="security" class="wpseotab">
<?php
$yform->checkbox( 'disableadvanced_meta', __( 'Disable the Advanced part of the WordPress SEO meta box', 'wordpress-seo' ) );
echo '<p class="desc">', __( 'Unchecking this box allows authors and editors to redirect posts, noindex them and do other things you might not want if you don\'t trust your authors.', 'wordpress-seo' ), '</p>';
?>
</div>
<?php
do_action( 'wpseo_dashboard' );
$wpseo_admin_pages->admin_footer();
$yform->admin_footer();
@@ -1,137 +0,0 @@
<?php
/**
* @package Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
global $wpseo_admin_pages;
$robots_file = get_home_path() . 'robots.txt';
$ht_access_file = get_home_path() . '.htaccess';
if ( isset( $_POST['create_robots'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot create a robots.txt file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo_create_robots' );
ob_start();
error_reporting( 0 );
do_robots();
$robots_content = ob_get_clean();
$f = fopen( $robots_file, 'x' );
fwrite( $f, $robots_content );
}
if ( isset( $_POST['submitrobots'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot edit the robots.txt file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo-robotstxt' );
if ( file_exists( $robots_file ) ) {
$robotsnew = stripslashes( $_POST['robotsnew'] );
if ( is_writable( $robots_file ) ) {
$f = fopen( $robots_file, 'w+' );
fwrite( $f, $robotsnew );
fclose( $f );
$msg = __( 'Updated Robots.txt', 'wordpress-seo' );
}
}
}
if ( isset( $_POST['submithtaccess'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot edit the .htaccess file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo-htaccess' );
if ( file_exists( $ht_access_file ) ) {
$ht_access_new = stripslashes( $_POST['htaccessnew'] );
if ( is_writeable( $ht_access_file ) ) {
$f = fopen( $ht_access_file, 'w+' );
fwrite( $f, $ht_access_new );
fclose( $f );
}
}
}
$wpseo_admin_pages->admin_header( false );
if ( isset( $msg ) && ! empty( $msg ) ) {
echo '<div id="message" style="width:94%;" class="updated fade"><p>' . esc_html( $msg ) . '</p></div>';
}
$action_url = network_admin_url( 'admin.php?page=wpseo_files' ); // auto-falls back on admin_url for non-multisite
if ( ! file_exists( $robots_file ) ) {
if ( is_writable( get_home_path() ) ) {
$content = '<form action="' . esc_url( $action_url ) . '" method="post" id="robotstxtcreateform">';
$content .= wp_nonce_field( 'wpseo_create_robots', '_wpnonce', true, false );
$content .= '<p>' . __( 'You don\'t have a robots.txt file, create one here:', 'wordpress-seo' ) . '</p>';
$content .= '<input type="submit" class="button" name="create_robots" value="' . __( 'Create robots.txt file', 'wordpress-seo' ) . '">';
$content .= '</form>';
}
else {
$content = '<p>' . __( 'If you had a robots.txt file and it was editable, you could edit it from here.', 'wordpress-seo' );
}
}
else {
$f = fopen( $robots_file, 'r' );
$content = '';
if ( filesize( $robots_file ) > 0 ) {
$content = fread( $f, filesize( $robots_file ) );
}
$robots_txt_content = esc_textarea( $content );
if ( ! is_writable( $robots_file ) ) {
$content = '<p><em>' . __( 'If your robots.txt were writable, you could edit it from here.', 'wordpress-seo' ) . '</em></p>';
$content .= '<textarea class="large-text code" disabled="disabled" rows="15" name="robotsnew">' . $robots_txt_content . '</textarea><br/>';
} else {
$content = '<form action="' . esc_url( $action_url ) . '" method="post" id="robotstxtform">';
$content .= wp_nonce_field( 'wpseo-robotstxt', '_wpnonce', true, false );
$content .= '<p>' . __( 'Edit the content of your robots.txt:', 'wordpress-seo' ) . '</p>';
$content .= '<textarea class="large-text code" rows="15" name="robotsnew">' . $robots_txt_content . '</textarea><br/>';
$content .= '<div class="submit"><input class="button" type="submit" name="submitrobots" value="' . __( 'Save changes to Robots.txt', 'wordpress-seo' ) . '" /></div>';
$content .= '</form>';
}
}
$wpseo_admin_pages->postbox( 'robotstxt', __( 'Robots.txt', 'wordpress-seo' ), $content );
if ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'nginx' ) === false ) && file_exists( $ht_access_file ) ) {
$f = fopen( $ht_access_file, 'r' );
$contentht = '';
if ( filesize( $ht_access_file ) > 0 ) {
$contentht = fread( $f, filesize( $ht_access_file ) );
}
$contentht = esc_textarea( $contentht );
if ( ! is_writable( $ht_access_file ) ) {
$content = '<p><em>' . __( 'If your .htaccess were writable, you could edit it from here.', 'wordpress-seo' ) . '</em></p>';
$content .= '<textarea class="large-text code" disabled="disabled" rows="15" name="robotsnew">' . $contentht . '</textarea><br/>';
} else {
$content = '<form action="' . esc_url( $action_url ) . '" method="post" id="htaccessform">';
$content .= wp_nonce_field( 'wpseo-htaccess', '_wpnonce', true, false );
$content .= '<p>' . __( 'Edit the content of your .htaccess:', 'wordpress-seo' ) . '</p>';
$content .= '<textarea class="large-text code" rows="15" name="htaccessnew">' . $contentht . '</textarea><br/>';
$content .= '<div class="submit"><input class="button" type="submit" name="submithtaccess" value="' . __( 'Save changes to .htaccess', 'wordpress-seo' ) . '" /></div>';
$content .= '</form>';
}
$wpseo_admin_pages->postbox( 'htaccess', __( '.htaccess file', 'wordpress-seo' ), $content );
} elseif ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'nginx' ) === false ) && ! file_exists( $ht_access_file ) ) {
$content = '<p>' . __( 'If you had a .htaccess file and it was editable, you could edit it from here.', 'wordpress-seo' );
$wpseo_admin_pages->postbox( 'htaccess', __( '.htaccess file', 'wordpress-seo' ), $content );
}
$wpseo_admin_pages->admin_footer( false );
@@ -1,508 +0,0 @@
<?php
/**
* @package Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* @todo [JRF => testers] Extensively test the export & import of the (new) settings!
* If that all works fine, getting testers to export before and after upgrade will make testing easier.
*
* @todo [Yoast] The import for the RSS Footer plugin checks for data already entered via WP SEO,
* the other import routines should do that too.
*/
global $wpseo_admin_pages;
$msg = '';
if ( isset( $_POST['import'] ) || isset( $_GET['import'] ) ) {
check_admin_referer( 'wpseo-import' );
global $wpdb;
$replace = false;
$deletekw = false;
if ( isset( $_POST['wpseo']['deleteolddata'] ) && $_POST['wpseo']['deleteolddata'] == 'on' ) {
$replace = true;
}
if ( isset( $_POST['wpseo']['importwoo'] ) ) {
WPSEO_Options::initialize();
$sep = get_option( 'seo_woo_seperator' );
$options = get_option( 'wpseo_titles' );
switch ( get_option( 'seo_woo_home_layout' ) ) {
case 'a':
$options['title-home-wpseo'] = '%%sitename%% ' . $sep . ' %%sitedesc%%';
break;
case 'b':
$options['title-home-wpseo'] = '%%sitename%% ' . get_option( 'seo_woo_paged_var' ) . ' %%pagenum%%';
break;
case 'c':
$options['title-home-wpseo'] = '%%sitedesc%%';
break;
}
if ( $replace ) {
delete_option( 'seo_woo_home_layout' );
}
switch ( get_option( 'seo_woo_single_layout' ) ) {
case 'a':
$options['title-post'] = '%%title%% ' . $sep . ' %%sitename%%';
break;
case 'b':
$options['title-post'] = '%%title%%';
break;
case 'c':
$options['title-post'] = '%%sitename%% ' . $sep . ' %%title%%';
break;
case 'd':
$options['title-post'] = '%%title%% ' . $sep . ' %%sitedesc%%';
break;
case 'e':
$options['title-post'] = '%%sitename%% ' . $sep . ' %%title%% ' . $sep . ' %%sitedesc%%';
break;
}
if ( $replace ) {
delete_option( 'seo_woo_single_layout' );
}
switch ( get_option( 'seo_woo_page_layout' ) ) {
case 'a':
$options['title-page'] = '%%title%% ' . $sep . ' %%sitename%%';
break;
case 'b':
$options['title-page'] = '%%title%%';
break;
case 'c':
$options['title-page'] = '%%sitename%% ' . $sep . ' %%title%%';
break;
case 'd':
$options['title-page'] = '%%title%% ' . $sep . ' %%sitedesc%%';
break;
case 'e':
$options['title-page'] = '%%sitename%% ' . $sep . ' %%title%% ' . $sep . ' %%sitedesc%%';
break;
}
if ( $replace ) {
delete_option( 'seo_woo_page_layout' );
}
$template = WPSEO_Options::get_default( 'wpseo_titles', 'title-tax-post' ); // the default is the same for all taxonomies, so post will do
switch ( get_option( 'seo_woo_archive_layout' ) ) {
case 'a':
$template = '%%term_title%% ' . $sep . ' %%page%% ' . $sep . ' %%sitename%%';
break;
case 'b':
$template = '%%term_title%%';
break;
case 'c':
$template = '%%sitename%% ' . $sep . ' %%term_title%% ' . $sep . ' %%page%%';
break;
case 'd':
$template = '%%term_title%% ' . $sep . ' %%page%%' . $sep . ' %%sitedesc%%';
break;
case 'e':
$template = '%%sitename%% ' . $sep . ' %%term_title%% ' . $sep . ' %%page%% ' . $sep . ' %%sitedesc%%';
break;
}
$taxonomies = get_taxonomies( array( 'public' => true ), 'names' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
foreach ( $taxonomies as $tax ) {
$options['title-tax-' . $tax] = $template;
}
}
unset( $taxonomies, $tax, $template );
if ( $replace ) {
delete_option( 'seo_woo_archive_layout' );
}
// Import the custom homepage description
if ( 'c' == get_option( 'seo_woo_meta_home_desc' ) ) {
$options['metadesc-home-wpseo'] = get_option( 'seo_woo_meta_home_desc_custom' );
}
if ( $replace ) {
delete_option( 'seo_woo_meta_home_desc' );
}
// Import the custom homepage keywords
if ( 'c' == get_option( 'seo_woo_meta_home_key' ) ) {
$options['metakey-home-wpseo'] = get_option( 'seo_woo_meta_home_key_custom' );
}
if ( $replace ) {
delete_option( 'seo_woo_meta_home_key' );
}
// If WooSEO is set to use the Woo titles, import those
if ( 'true' == get_option( 'seo_woo_wp_title' ) ) {
WPSEO_Meta::replace_meta( 'seo_title', WPSEO_Meta::$meta_prefix . 'title', $replace );
}
// If WooSEO is set to use the Woo meta descriptions, import those
if ( 'b' == get_option( 'seo_woo_meta_single_desc' ) ) {
WPSEO_Meta::replace_meta( 'seo_description', WPSEO_Meta::$meta_prefix . 'metadesc', $replace );
}
// If WooSEO is set to use the Woo meta keywords, import those
if ( 'b' == get_option( 'seo_woo_meta_single_key' ) ) {
WPSEO_Meta::replace_meta( 'seo_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $replace );
}
/* @todo [JRF => whomever] verify how WooSEO sets these metas ( 'noindex', 'follow' )
* and if the values saved are concurrent with the ones we use (i.e. 0/1/2) */
WPSEO_Meta::replace_meta( 'seo_follow', WPSEO_Meta::$meta_prefix . 'meta-robots-nofollow', $replace );
WPSEO_Meta::replace_meta( 'seo_noindex', WPSEO_Meta::$meta_prefix . 'meta-robots-noindex', $replace );
update_option( 'wpseo_titles', $options );
$msg .= __( 'WooThemes SEO framework settings &amp; data successfully imported.', 'wordpress-seo' );
unset( $options, $sep );
}
if ( isset( $_POST['wpseo']['importheadspace'] ) ) {
WPSEO_Meta::replace_meta( '_headspace_description', WPSEO_Meta::$meta_prefix . 'metadesc', $replace );
WPSEO_Meta::replace_meta( '_headspace_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $replace );
WPSEO_Meta::replace_meta( '_headspace_page_title', WPSEO_Meta::$meta_prefix . 'title', $replace );
/* @todo [JRF => whomever] verify how headspace sets these metas ( 'noindex', 'nofollow', 'noarchive', 'noodp', 'noydir' )
* and if the values saved are concurrent with the ones we use (i.e. 0/1/2) */
WPSEO_Meta::replace_meta( '_headspace_noindex', WPSEO_Meta::$meta_prefix . 'meta-robots-noindex', $replace );
WPSEO_Meta::replace_meta( '_headspace_nofollow', WPSEO_Meta::$meta_prefix . 'meta-robots-nofollow', $replace );
/* @todo - [JRF => whomever] check if this can be done more efficiently by querying only the meta table
* possibly directly changing it using concat on the existing values
*/
$posts = $wpdb->get_results( "SELECT ID FROM $wpdb->posts" );
if ( is_array( $posts ) && $posts !== array() ) {
foreach ( $posts as $post ) {
$custom = get_post_custom( $post->ID );
$robotsmeta_adv = '';
if ( isset( $custom['_headspace_noarchive'] ) ) {
$robotsmeta_adv .= 'noarchive,';
}
if ( isset( $custom['_headspace_noodp'] ) ) {
$robotsmeta_adv .= 'noodp,';
}
if ( isset( $custom['_headspace_noydir'] ) ) {
$robotsmeta_adv .= 'noydir';
}
$robotsmeta_adv = preg_replace( '`,$`', '', $robotsmeta_adv );
WPSEO_Meta::set_value( 'meta-robots-adv', $robotsmeta_adv, $post->ID );
}
}
unset( $posts, $post, $custom, $robotsmeta_adv );
if ( $replace ) {
foreach ( array( 'noarchive', 'noodp', 'noydir' ) as $meta ) {
delete_post_meta_by_key( '_headspace_' . $meta );
}
unset( $meta );
}
$msg .= __( 'HeadSpace2 data successfully imported', 'wordpress-seo' );
}
// @todo [JRF => whomever] how does this correlate with the routine on the dashboard page ? isn't one superfluous ?
if ( isset( $_POST['wpseo']['importaioseo'] ) || isset( $_GET['importaioseo'] ) ) {
WPSEO_Meta::replace_meta( '_aioseop_description', WPSEO_Meta::$meta_prefix . 'metadesc', $replace );
WPSEO_Meta::replace_meta( '_aioseop_keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $replace );
WPSEO_Meta::replace_meta( '_aioseop_title', WPSEO_Meta::$meta_prefix . 'title', $replace );
$options_aiosep = get_option( 'aioseop_options' );
if ( isset( $options_aiosep['aiosp_google_analytics_id'] ) ) {
/**
* The Google Analytics settings are used
*/
$ga_universal = 0;
$ga_trackoutbound = 0;
$ga_anomip = 0;
if ( $options_aiosep['aiosp_ga_use_universal_analytics'] == 'on' ) {
$ga_universal = 1;
}
if ( $options_aiosep['aiosp_ga_track_outbound_links'] == 'on' ) {
$ga_trackoutbound = 1;
}
if( $options_aiosep['aiosp_ga_anonymize_ip'] == 'on' ){
}
$ga_settings = array(
'manual_ua_code' => (int) 1,
'manual_ua_code_field' => $options_aiosep['aiosp_google_analytics_id'],
'enable_universal' => (int) $ga_universal,
'track_outbound' => (int) $ga_trackoutbound,
'ignore_users' => (array) $options_aiosep['aiosp_ga_exclude_users'],
'anonymize_ips' => (int) $ga_anomip,
);
if( get_option('yst_ga') == false ){
$options['ga_general'] = $ga_settings;
update_option( 'yst_ga', $options );
}
$plugin_install_nonce = wp_create_nonce('install-plugin_google-analytics-for-wordpress'); // Use the old name because that's the WordPress.org repo
$msg .= __( sprintf(
'All in One SEO data successfully imported. Would you like to %sdisable the All in One SEO plugin%s. You\'ve had Google Analytics enabled in All in One SEO, would you like to install our %sGoogle Analytics plugin%s?',
'<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_import&deactivate_aioseo=1' ) ) . '">',
'</a>',
'<a href="' . esc_url( admin_url( 'update.php?action=install-plugin&plugin=google-analytics-for-wordpress&_wpnonce=' . $plugin_install_nonce ) ) . '">',
'</a>'
), 'wordpress-seo' );
} else {
$msg .= __( sprintf( 'All in One SEO data successfully imported. Would you like to %sdisable the All in One SEO plugin%s.', '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_import&deactivate_aioseo=1' ) ) . '">', '</a>' ), 'wordpress-seo' );
}
}
if ( isset( $_POST['wpseo']['importaioseoold'] ) ) {
WPSEO_Meta::replace_meta( 'description', WPSEO_Meta::$meta_prefix . 'metadesc', $replace );
WPSEO_Meta::replace_meta( 'keywords', WPSEO_Meta::$meta_prefix . 'metakeywords', $replace );
WPSEO_Meta::replace_meta( 'title', WPSEO_Meta::$meta_prefix . 'title', $replace );
$msg .= __( 'All in One SEO (Old version) data successfully imported.', 'wordpress-seo' );
}
if ( isset( $_POST['wpseo']['importrobotsmeta'] ) || isset( $_GET['importrobotsmeta'] ) ) {
$posts = $wpdb->get_results( "SELECT ID, robotsmeta FROM $wpdb->posts" );
if ( is_array( $posts ) && $posts !== array() ) {
foreach ( $posts as $post ) {
// sync all possible settings
if ( $post->robotsmeta ) {
$pieces = explode( ',', $post->robotsmeta );
foreach ( $pieces as $meta ) {
switch ( $meta ) {
case 'noindex':
WPSEO_Meta::set_value( 'meta-robots-noindex', '1', $post->ID );
break;
case 'index':
WPSEO_Meta::set_value( 'meta-robots-noindex', '2', $post->ID );
break;
case 'nofollow':
WPSEO_Meta::set_value( 'meta-robots-nofollow', '1', $post->ID );
break;
}
}
}
}
}
unset( $posts, $post, $pieces, $meta );
$msg .= __( sprintf( 'Robots Meta values imported. We recommend %sdisabling the Robots-Meta plugin%s to avoid any conflicts.', '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_import&deactivate_robots_meta=1' ) ) . '">', '</a>' ), 'wordpress-seo' );
}
if ( isset( $_POST['wpseo']['importrssfooter'] ) ) {
$optold = get_option( 'RSSFooterOptions' );
$optnew = get_option( 'wpseo_rss' );
if ( $optold['position'] == 'after' ) {
if ( $optnew['rssafter'] === '' || $optnew['rssafter'] === WPSEO_Options::get_default( 'wpseo_rss', 'rssafter' ) ) {
$optnew['rssafter'] = $optold['footerstring'];
}
} else {
/* @internal Uncomment the second part if a default would be given to the rssbefore value */
if ( $optnew['rssbefore'] === '' /*|| $optnew['rssbefore'] === WPSEO_Options::get_default( 'wpseo_rss', 'rssbefore' )*/ ) {
$optnew['rssbefore'] = $optold['footerstring'];
}
}
update_option( 'wpseo_rss', $optnew );
unset( $optold, $optnew );
$msg .= __( 'RSS Footer options imported successfully.', 'wordpress-seo' );
}
if ( isset( $_POST['wpseo']['importbreadcrumbs'] ) ) {
$optold = get_option( 'yoast_breadcrumbs' );
$optnew = get_option( 'wpseo_internallinks' );
if ( is_array( $optold ) && $optold !== array() ) {
foreach ( $optold as $opt => $val ) {
if ( is_bool( $val ) && $val == true ) {
$optnew['breadcrumbs-' . $opt] = true;
} else {
$optnew['breadcrumbs-' . $opt] = $val;
}
}
unset( $opt, $val );
update_option( 'wpseo_internallinks', $optnew );
$msg .= __( 'Yoast Breadcrumbs options imported successfully.', 'wordpress-seo' );
} else {
$msg .= __( 'Yoast Breadcrumbs options could not be found', 'wordpress-seo' );
}
unset( $optold, $optnew );
}
// Allow custom import actions
do_action( 'wpseo_handle_import' );
/**
* Allow customization of import&export message
* @api string $msg The message.
*/
$msg = apply_filters( 'wpseo_import_message', $msg );
// Check if we've deleted old data and adjust message to match it
if ( $replace ) {
$msg .= __( ', and old data deleted.', 'wordpress-seo' );
}
if ( $deletekw ) {
$msg .= __( ', and meta keywords data deleted.', 'wordpress-seo' );
}
}
$wpseo_admin_pages->admin_header( false );
if ( $msg != '' ) {
echo '<div id="message" class="message updated" style="width:94%;"><p>' . $msg . '</p></div>';
}
$content = '<p>' . __( 'No doubt you\'ve used an SEO plugin before if this site isn\'t new. Let\'s make it easy on you, you can import the data below. If you want, you can import first, check if it was imported correctly, and then import &amp; delete. No duplicate data will be imported.', 'wordpress-seo' ) . '</p>';
$content .= '<p>' . sprintf( __( 'If you\'ve used another SEO plugin, try the %sSEO Data Transporter%s plugin to move your data into this plugin, it rocks!', 'wordpress-seo' ), '<a href="https://wordpress.org/plugins/seo-data-transporter/">', '</a>' ) . '</p>';
// @todo [JRF => whomever] add action for form tag
$content .= '<form action="" method="post" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
$content .= wp_nonce_field( 'wpseo-import', '_wpnonce', true, false );
$content .= $wpseo_admin_pages->checkbox( 'importheadspace', __( 'Import from HeadSpace2?', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->checkbox( 'importaioseo', __( 'Import from All-in-One SEO?', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->checkbox( 'importaioseoold', __( 'Import from OLD All-in-One SEO?', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->checkbox( 'importwoo', __( 'Import from WooThemes SEO framework?', 'wordpress-seo' ) );
$content .= '<br/>';
$content .= $wpseo_admin_pages->checkbox( 'deleteolddata', __( 'Delete the old data after import? (recommended)', 'wordpress-seo' ) );
$content .= '<br/>';
$content .= '<input type="submit" class="button-primary" name="import" value="' . __( 'Import', 'wordpress-seo' ) . '" />';
$content .= '<br/><br/>';
$content .= '<h2>' . __( 'Import settings from other plugins', 'wordpress-seo' ) . '</h2>';
$content .= $wpseo_admin_pages->checkbox( 'importrobotsmeta', __( 'Import from Robots Meta (by Yoast)?', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->checkbox( 'importrssfooter', __( 'Import from RSS Footer (by Yoast)?', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->checkbox( 'importbreadcrumbs', __( 'Import from Yoast Breadcrumbs?', 'wordpress-seo' ) );
/**
* Allow option of importing from other 'other' plugins
* @api string $content The content containing all import and export methods
*/
$content = apply_filters( 'wpseo_import_other_plugins', $content );
$content .= '<br/>';
$content .= '<input type="submit" class="button-primary" name="import" value="' . __( 'Import', 'wordpress-seo' ) . '" />';
$content .= '</form><br/>';
$wpseo_admin_pages->postbox( 'import', __( 'Import', 'wordpress-seo' ), $content );
/**
* Allow adding a custom import block
* @api WPSEO_Admin $this The WPSEO_Admin object
*/
do_action( 'wpseo_import', $this );
// @todo [JRF => whomever] add action for form tag
$content = '<h4>' . __( 'Export', 'wordpress-seo' ) . '</h4>';
$content .= '<form action="" method="post" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
$content .= wp_nonce_field( 'wpseo-export', '_wpnonce', true, false );
$content .= '<p>' . __( 'Export your WordPress SEO settings here, to import them again later or to import them on another site.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'include_taxonomy_meta', __( 'Include Taxonomy Metadata', 'wordpress-seo' ) );
$content .= '<br/><input type="submit" class="button" name="wpseo_export" value="' . __( 'Export settings', 'wordpress-seo' ) . '"/>';
$content .= '</form>';
if ( isset( $_POST['wpseo_export'] ) ) {
check_admin_referer( 'wpseo-export' );
$include_taxonomy = false;
if ( isset( $_POST['wpseo']['include_taxonomy_meta'] ) ) {
$include_taxonomy = true;
}
$url = $wpseo_admin_pages->export_settings( $include_taxonomy );
if ( $url ) {
$GLOBALS['export_js'] = '
<script type="text/javascript">
document.location = \'' . $url . '\';
</script>';
add_action( 'admin_footer-' . $GLOBALS['hook_suffix'], 'wpseo_deliver_export_zip' );
} else {
$content .= 'Error: ' . $url;
}
}
$content .= '<h4>' . __( 'Import', 'wordpress-seo' ) . '</h4>';
if ( ! isset( $_FILES['settings_import_file'] ) || empty( $_FILES['settings_import_file'] ) ) {
$content .= '<p>' . __( 'Import settings by locating <em>settings.zip</em> and clicking', 'wordpress-seo' ) . ' "' . __( 'Import settings', 'wordpress-seo' ) . '":</p>';
// @todo [JRF => whomever] add action for form tag
$content .= '<form action="" method="post" enctype="multipart/form-data" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
$content .= wp_nonce_field( 'wpseo-import-file', '_wpnonce', true, false );
$content .= '<input type="file" name="settings_import_file"/>';
$content .= '<input type="hidden" name="action" value="wp_handle_upload"/>';
$content .= '<input type="submit" class="button" value="' . __( 'Import settings', 'wordpress-seo' ) . '"/>';
$content .= '</form><br/>';
} elseif ( isset( $_FILES['settings_import_file'] ) ) {
check_admin_referer( 'wpseo-import-file' );
$file = wp_handle_upload( $_FILES['settings_import_file'] );
if ( isset( $file['file'] ) && ! is_wp_error( $file ) ) {
$upload_dir = wp_upload_dir();
if ( ! defined( 'DIRECTORY_SEPARATOR' ) ) {
define( 'DIRECTORY_SEPARATOR', '/' );
}
$p_path = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'wpseo-import' . DIRECTORY_SEPARATOR;
if ( ! isset( $GLOBALS['wp_filesystem'] ) || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
WP_Filesystem();
}
$unzipped = unzip_file( $file['file'], $p_path );
if ( ! is_wp_error( $unzipped ) ) {
$filename = $p_path . 'settings.ini';
if ( @is_file( $filename ) && is_readable( $filename ) ) {
$options = parse_ini_file( $filename, true );
if ( is_array( $options ) && $options !== array() ) {
$old_wpseo_version = null;
if ( isset( $options['wpseo']['version'] ) && $options['wpseo']['version'] !== '' ) {
$old_wpseo_version = $options['wpseo']['version'];
}
foreach ( $options as $name => $optgroup ) {
if ( $name === 'wpseo_taxonomy_meta' ) {
$optgroup = json_decode( urldecode( $optgroup['wpseo_taxonomy_meta'] ), true );
}
// Make sure that the imported options are cleaned/converted on import
$option_instance = WPSEO_Options::get_option_instance( $name );
if ( is_object( $option_instance ) && method_exists( $option_instance, 'import' ) ) {
$optgroup = $option_instance->import( $optgroup, $old_wpseo_version, $options );
} elseif ( WP_DEBUG === true || ( defined( 'WPSEO_DEBUG' ) && WPSEO_DEBUG === true ) ) {
$content .= '<p><strong>' . sprintf( __( 'Setting "%s" is no longer used and has been discarded.', 'wordpress-seo' ), $name ) . '</strong></p>';
}
}
$content .= '<p><strong>' . __( 'Settings successfully imported.', 'wordpress-seo' ) . '</strong></p>';
} else {
$content .= '<p><strong>' . __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'No settings found in file.', 'wordpress-seo' ) . '</strong></p>';
}
unset( $options, $name, $optgroup );
} else {
$content .= '<p><strong>' . __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'Unzipping failed - file settings.ini not found.', 'wordpress-seo' ) . '</strong></p>';
}
@unlink( $filename );
@unlink( $p_path );
} else {
$content .= '<p><strong>' . __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . sprintf( __( 'Unzipping failed with error "%s".', 'wordpress-seo' ), $unzipped->get_error_message() ) . '</strong></p>';
}
unset( $zip, $unzipped );
@unlink( $file['file'] );
} else {
if ( is_wp_error( $file ) ) {
$content .= '<p><strong>' . __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . $file->get_error_message() . '</strong></p>';
} else {
$content .= '<p><strong>' . __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'Upload failed.', 'wordpress-seo' ) . '</strong></p>';
}
}
}
$wpseo_admin_pages->postbox( 'wpseo_export', __( 'Export & Import SEO Settings', 'wordpress-seo' ), $content );
$wpseo_admin_pages->admin_footer( false );
function wpseo_deliver_export_zip() {
if ( isset( $GLOBALS['export_js'] ) && $GLOBALS['export_js'] !== '' ) {
echo $GLOBALS['export_js'];
}
}
@@ -1,83 +0,0 @@
<?php
/**
* @package Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
global $wpseo_admin_pages;
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_internallinks' ), 'wpseo_internallinks' );
$content = $wpseo_admin_pages->checkbox( 'breadcrumbs-enable', __( 'Enable Breadcrumbs', 'wordpress-seo' ) );
$content .= '<br/>';
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-sep', __( 'Separator between breadcrumbs', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-home', __( 'Anchor text for the Homepage', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-prefix', __( 'Prefix for the breadcrumb path', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-archiveprefix', __( 'Prefix for Archive breadcrumbs', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-searchprefix', __( 'Prefix for Search Page breadcrumbs', 'wordpress-seo' ) );
$content .= $wpseo_admin_pages->textinput( 'breadcrumbs-404crumb', __( 'Breadcrumb for 404 Page', 'wordpress-seo' ) );
if ( get_option( 'show_on_front' ) == 'page' && get_option( 'page_for_posts' ) > 0 ) {
$content .= $wpseo_admin_pages->checkbox( 'breadcrumbs-blog-remove', __( 'Remove Blog page from Breadcrumbs', 'wordpress-seo' ) );
}
$content .= $wpseo_admin_pages->checkbox( 'breadcrumbs-boldlast', __( 'Bold the last page in the breadcrumb', 'wordpress-seo' ) );
$content .= '<br/><br/>';
$post_types = get_post_types( array( 'public' => true ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
$content .= '<strong>' . __( 'Taxonomy to show in breadcrumbs for:', 'wordpress-seo' ) . '</strong><br/>';
foreach ( $post_types as $pt ) {
$taxonomies = get_object_taxonomies( $pt->name, 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
$values = array( 0 => __( 'None', 'wordpress-seo' ) );
foreach ( $taxonomies as $tax ) {
$values[ $tax->name ] = $tax->labels->singular_name;
}
$content .= $wpseo_admin_pages->select( 'post_types-' . $pt->name . '-maintax', $pt->labels->name, $values );
unset( $values, $tax );
}
unset( $taxonomies );
}
unset( $pt );
}
$content .= '<br/>';
$taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false ), 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
$content .= '<strong>' . __( 'Post type archive to show in breadcrumbs for:', 'wordpress-seo' ) . '</strong><br/>';
foreach ( $taxonomies as $tax ) {
$values = array( 0 => __( 'None', 'wordpress-seo' ) );
if ( get_option( 'show_on_front' ) == 'page' && get_option( 'page_for_posts' ) > 0 ) {
$values['post'] = __( 'Blog', 'wordpress-seo' );
}
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $pt ) {
if ( $pt->has_archive ) {
$values[ $pt->name ] = $pt->labels->name;
}
}
unset( $pt );
}
$content .= $wpseo_admin_pages->select( 'taxonomy-' . $tax->name . '-ptparent', $tax->labels->singular_name, $values );
unset( $values, $tax );
}
}
unset( $taxonomies, $post_types );
$content .= '<br class="clear"/>';
$content .= '<h4>' . __( 'How to insert breadcrumbs in your theme', 'wordpress-seo' ) . '</h4>';
$content .= '<p>' . __( 'Usage of this breadcrumbs feature is explained <a href="https://yoast.com/wordpress/plugins/breadcrumbs/">here</a>. For the more code savvy, insert this in your theme:', 'wordpress-seo' ) . '</p>';
$content .= '<pre>&lt;?php if ( function_exists(&#x27;yoast_breadcrumb&#x27;) ) {
yoast_breadcrumb(&#x27;&lt;p id=&quot;breadcrumbs&quot;&gt;&#x27;,&#x27;&lt;/p&gt;&#x27;);
} ?&gt;</pre>';
$wpseo_admin_pages->postbox( 'internallinks', __( 'Breadcrumbs Settings', 'wordpress-seo' ), $content );
$wpseo_admin_pages->admin_footer();
@@ -1,7 +1,7 @@
<?php
/**
* @package Admin
* @todo Add default content (when no premium plugins are activated)
* @package WPSEO\Admin
* @since 1.5.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -10,12 +10,63 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$extensions = array(
'seo-premium' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/seo-premium/',
'title' => __( 'WordPress SEO Premium', 'wordpress-seo' ),
'desc' => __( 'The premium version of WordPress SEO with more features & support.', 'wordpress-seo' ),
'installed' => false,
),
'video-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/video-seo/',
'title' => __( 'Video SEO', 'wordpress-seo' ),
'desc' => __( 'Optimize your videos to show them off in search results and get more clicks!', 'wordpress-seo' ),
'installed' => false,
),
'news-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/news-seo/',
'title' => __( 'News SEO', 'wordpress-seo' ),
'desc' => __( 'Are you in Google News? Increase your traffic from Google News by optimizing for it!', 'wordpress-seo' ),
'installed' => false,
),
'local-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/local-seo/',
'title' => __( 'Local SEO', 'wordpress-seo' ),
'desc' => __( 'Rank better locally and in Google Maps, without breaking a sweat!', 'wordpress-seo' ),
'installed' => false,
),
'woocommerce-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/',
'title' => __( 'Yoast WooCommerce SEO', 'wordpress-seo' ),
'desc' => __( 'Seamlessly integrate WooCommerce with WordPress SEO and get extra features!', 'wordpress-seo' ),
'installed' => false,
)
);
if ( class_exists( 'WPSEO_Premium' ) ) {
$extensions['seo-premium']->installed = true;
}
if ( class_exists( 'wpseo_Video_Sitemap' ) ) {
$extensions['video-seo']->installed = true;
}
if ( class_exists( 'WPSEO_News' ) ) {
$extensions['news-seo']->installed = true;
}
if ( defined( 'WPSEO_LOCAL_VERSION' ) ) {
$extensions['local-seo']->installed = true;
}
if ( ! class_exists( 'Woocommerce' ) ) {
unset( $extensions['woocommerce-seo'] );
}
elseif ( class_exists( 'Yoast_WooCommerce_SEO' ) ) {
$extensions['woocommerce-seo']->installed = true;
}
?>
<div class="wrap wpseo_table_page">
<h2 id="wpseo-title"><?php echo esc_html( get_admin_page_title() ); ?></h2>
<h2 id="wpseo-title"><?php _e( 'WordPress SEO Extensions', 'wordpress-seo' ); ?></h2>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="extensions-tab" href="#top#extensions"><?php _e( 'Extensions', 'wordpress-seo' ); ?></a>
@@ -25,59 +76,6 @@ global $wpseo_admin_pages;
<div class="tabwrapper">
<div id="extensions" class="wpseotab">
<?php
$extensions = array(
'seo-premium' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/seo-premium/',
'title' => __( 'WordPress SEO Premium', 'wordpress-seo' ),
'desc' => __( 'The premium version of WordPress SEO with more features & support.', 'wordpress-seo' ),
'installed' => false,
),
'video-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/video-seo/',
'title' => __( 'Video SEO', 'wordpress-seo' ),
'desc' => __( 'Optimize your videos to show them off in search results and get more clicks!', 'wordpress-seo' ),
'installed' => false,
),
'news-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/news-seo/',
'title' => __( 'News SEO', 'wordpress-seo' ),
'desc' => __( 'Are you in Google News? Increase your traffic from Google News by optimizing for it!', 'wordpress-seo' ),
'installed' => false,
),
'local-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/local-seo/',
'title' => __( 'Local SEO', 'wordpress-seo' ),
'desc' => __( 'Rank better locally and in Google Maps, without breaking a sweat!', 'wordpress-seo' ),
'installed' => false,
),
'woocommerce-seo' => (object) array(
'url' => 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/',
'title' => __( 'Yoast WooCommerce SEO', 'wordpress-seo' ),
'desc' => __( 'Seamlessly integrate WooCommerce with WordPress SEO and get extra features!', 'wordpress-seo' ),
'installed' => false,
)
);
if ( class_exists( 'WPSEO_Premium' ) ) {
$extensions['seo-premium']->installed = true;
}
if ( class_exists( 'wpseo_Video_Sitemap' ) ) {
$extensions['video-seo']->installed = true;
}
if ( class_exists( 'WPSEO_News' ) ) {
$extensions['news-seo']->installed = true;
}
if ( defined( 'WPSEO_LOCAL_VERSION' ) ) {
$extensions['local-seo']->installed = true;
}
if ( ! class_exists( 'Woocommerce' ) ) {
unset( $extensions['woocommerce-seo'] );
} else {
if ( class_exists( 'Yoast_WooCommerce_SEO' ) ) {
$extensions['woocommerce-seo']->installed = true;
}
}
foreach ( $extensions as $id => $extension ) {
$utm = '#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=extension-page-banners';
?>
@@ -89,17 +87,18 @@ global $wpseo_admin_pages;
<p><?php echo esc_html( $extension->desc ); ?></p>
<p>
<?php if ( $extension->installed ) { ?>
<?php if ( $extension->installed ) : ?>
<button class="button-primary installed">Installed</button>
<?php } else { ?>
<?php else : ?>
<a target="_blank" href="<?php echo esc_url( $extension->url . $utm ); ?>" class="button-primary">
<?php esc_html_e( 'Get this extension', 'wordpress-seo' ); ?>
<?php _e( 'Get this extension', 'wordpress-seo' ); ?>
</a>
<?php } ?>
<?php endif; ?>
</p>
</div>
<?php
}
unset( $extensions, $id, $extension, $utm );
?>
</div>
<div id="licenses" class="wpseotab">
@@ -109,7 +108,12 @@ global $wpseo_admin_pages;
* Display license page
*/
settings_errors();
do_action( 'wpseo_licenses_forms' );
if ( ! has_action( 'wpseo_licenses_forms' ) ) {
echo '<div class="msg"><p>', __( 'This is where you would enter the license keys for one of our premium plugins, should you activate one.', 'wordpress-seo' ), '</p></div>';
}
else {
do_action( 'wpseo_licenses_forms' );
}
?>
</div>
</div>
@@ -1,6 +1,6 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,201 +9,215 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$options = WPSEO_Options::get_all();
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_titles' ), 'wpseo_titles' );
$yform = Yoast_Form::get_instance();
$yform->admin_header( true, 'wpseo_titles' );
?>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="general-tab" href="#top#general"><?php _e( 'General', 'wordpress-seo' );?></a>
<a class="nav-tab" id="home-tab" href="#top#home"><?php _e( 'Home', 'wordpress-seo' );?></a>
<a class="nav-tab" id="post_types-tab" href="#top#post_types"><?php _e( 'Post Types', 'wordpress-seo' );?></a>
<a class="nav-tab" id="taxonomies-tab" href="#top#taxonomies"><?php _e( 'Taxonomies', 'wordpress-seo' );?></a>
<a class="nav-tab" id="archives-tab" href="#top#archives"><?php _e( 'Other', 'wordpress-seo' );?></a>
</h2>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="general-tab" href="#top#general"><?php _e( 'General', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="home-tab" href="#top#home"><?php _e( 'Homepage', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="post_types-tab" href="#top#post_types"><?php _e( 'Post Types', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="taxonomies-tab" href="#top#taxonomies"><?php _e( 'Taxonomies', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="archives-tab" href="#top#archives"><?php _e( 'Archives', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="other-tab" href="#top#other"><?php _e( 'Other', 'wordpress-seo' ); ?></a>
</h2>
<div class="tabwrapper">
<div id="general" class="wpseotab">
<?php
echo '<h2>' . __( 'Title settings', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->checkbox( 'forcerewritetitle', __( 'Force rewrite titles', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'WordPress SEO has auto-detected whether it needs to force rewrite the titles for your pages, if you think it\'s wrong and you know what you\'re doing, you can change the setting here.', 'wordpress-seo' ) . '</p>';
echo '<h2>' . __( 'Title Separator', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->radio( 'separator', WPSEO_Option_Titles::get_instance()->get_separator_options(), '' );
echo '<p class="desc">' . __( 'Choose the symbol to use as your title separator. This will display, for instance, between your post title and site name.', 'wordpress-seo' ) . ' ' . __( 'Symbols are shown in the size they\'ll appear in in search results.', 'wordpress-seo' ) . '</p>';
echo '<h2>' . __( 'Sitewide <code>meta</code> settings', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->checkbox( 'noindex-subpages-wpseo', __( 'Noindex subpages of archives', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'If you want to prevent /page/2/ and further of any archive to show up in the search results, enable this.', 'wordpress-seo' ) . '</p>';
echo $wpseo_admin_pages->checkbox( 'usemetakeywords', __( 'Use <code>meta</code> keywords tag?', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'I don\'t know why you\'d want to use meta keywords, but if you want to, check this box.', 'wordpress-seo' ) . '</p>';
echo $wpseo_admin_pages->checkbox( 'noodp', __( 'Add <code>noodp</code> meta robots tag sitewide', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'Prevents search engines from using the DMOZ description for pages from this site in the search results.', 'wordpress-seo' ) . '</p>';
echo $wpseo_admin_pages->checkbox( 'noydir', __( 'Add <code>noydir</code> meta robots tag sitewide', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'Prevents search engines from using the Yahoo! directory description for pages from this site in the search results.', 'wordpress-seo' ) . '</p>';
echo '<h2>' . __( 'Clean up the <code>&lt;head&gt;</code>', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->checkbox( 'hide-rsdlink', __( 'Hide RSD Links', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'hide-wlwmanifest', __( 'Hide WLW Manifest Links', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'hide-shortlink', __( 'Hide Shortlink for posts', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'hide-feedlinks', __( 'Hide RSS Links', 'wordpress-seo' ) );
?>
</div>
<div id="home" class="wpseotab">
<?php
if ( 'posts' == get_option( 'show_on_front' ) ) {
echo '<h2>' . __( 'Homepage', 'wordpress-seo' ) . '</h2>';
echo $wpseo_admin_pages->textinput( 'title-home-wpseo', __( 'Title template', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-home-wpseo', __( 'Meta description template', 'wordpress-seo' ), '', 'metadesc' );
if ( $options['usemetakeywords'] === true ) {
echo $wpseo_admin_pages->textinput( 'metakey-home-wpseo', __( 'Meta keywords template', 'wordpress-seo' ) );
}
}
else {
echo '<h2>' . __( 'Homepage &amp; Front page', 'wordpress-seo' ) . '</h2>';
echo '<p>' . sprintf( __( 'You can determine the title and description for the front page by %sediting the front page itself &raquo;%s', 'wordpress-seo' ), '<a href="' . esc_url( get_edit_post_link( get_option( 'page_on_front' ) ) ) . '">', '</a>' ) . '</p>';
if ( get_option( 'page_for_posts' ) > 0 ) {
echo '<p>' . sprintf( __( 'You can determine the title and description for the blog page by %sediting the blog page itself &raquo;%s', 'wordpress-seo' ), '<a href="' . esc_url( get_edit_post_link( get_option( 'page_for_posts' ) ) ) . '">', '</a>' ) . '</p>';
}
}
?>
</div>
<div id="post_types" class="wpseotab">
<?php
$post_types = get_post_types( array( 'public' => true ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $pt ) {
$warn = false;
if ( $options['redirectattachment'] === true && $pt->name == 'attachment' ) {
echo '<div class="wpseo-warning">';
$warn = true;
<div class="tabwrapper">
<div id="general" class="wpseotab">
<table class="form-table">
<tr>
<th>
<?php _e( 'Force rewrite titles', 'wordpress-seo' ); ?>
</th>
<td>
<?php
$yform->checkbox( 'forcerewritetitle', __( 'Enable force rewrite titles', 'wordpress-seo' ) );
echo '<p class="description">', __( 'WordPress SEO has auto-detected whether it needs to force rewrite the titles for your pages, if you think it\'s wrong and you know what you\'re doing, you can change the setting here.', 'wordpress-seo' ), '</p>';
?>
</td>
</tr>
<tr>
<th>
<?php _e( 'Title Separator', 'wordpress-seo' ); ?>
</th>
<td>
<?php
$yform->radio( 'separator', WPSEO_Option_Titles::get_instance()->get_separator_options(), '' );
echo '<p class="description">', __( 'Choose the symbol to use as your title separator. This will display, for instance, between your post title and site name.', 'wordpress-seo' ), ' ', __( 'Symbols are shown in the size they\'ll appear in in search results.', 'wordpress-seo' ), '</p>';
?>
</td>
</tr>
</table>
</div>
<div id="home" class="wpseotab">
<?php
if ( 'posts' == get_option( 'show_on_front' ) ) {
echo '<p><strong>', __( 'Homepage', 'wordpress-seo' ), '</strong><br/>';
$yform->textinput( 'title-home-wpseo', __( 'Title template', 'wordpress-seo' ), 'template homepage-template' );
$yform->textarea( 'metadesc-home-wpseo', __( 'Meta description template', 'wordpress-seo' ), array( 'class' => 'template homepage-template' ) );
if ( $options['usemetakeywords'] === true ) {
$yform->textinput( 'metakey-home-wpseo', __( 'Meta keywords template', 'wordpress-seo' ) );
}
echo '</p>';
}
$name = $pt->name;
echo '<h4 id="' . esc_attr( $name ) . '">' . esc_html( ucfirst( $pt->labels->name ) ) . '</h4>';
if ( $warn === true ) {
echo '<h4 class="error-message">' . __( 'Take note:', 'wordpress-seo' ) . '</h4>';
echo '<p class="error-message">' . __( 'As you are redirecting attachment URLs to parent post URLs, these settings will currently only have an effect on <strong>unattached</strong> media items!', 'wordpress-seo' ) . '</p>';
echo '<p class="error-message">' . sprintf( __( 'So remember: If you change the %sattachment redirection setting%s in the future, the below settings will take effect for *all* media items.', 'wordpress-seo' ), '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_permalinks' ) ) . '">', '</a>' ) . '</p>';
else {
echo '<p><strong>', __( 'Homepage &amp; Front page', 'wordpress-seo' ), '</strong><br/>';
printf( __( 'You can determine the title and description for the front page by %sediting the front page itself &raquo;%s', 'wordpress-seo' ), '<a href="' . esc_url( get_edit_post_link( get_option( 'page_on_front' ) ) ) . '">', '</a>' );
echo '</p>';
if ( get_option( 'page_for_posts' ) > 0 ) {
echo '<p>', sprintf( __( 'You can determine the title and description for the blog page by %sediting the blog page itself &raquo;%s', 'wordpress-seo' ), '<a href="' . esc_url( get_edit_post_link( get_option( 'page_for_posts' ) ) ) . '">', '</a>' ), '</p>';
}
}
?>
</div>
<div id="post_types" class="wpseotab">
<?php
$post_types = get_post_types( array( 'public' => true ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $pt ) {
$warn = false;
if ( $options['redirectattachment'] === true && $pt->name == 'attachment' ) {
echo '<div class="wpseo-warning">';
$warn = true;
}
echo $wpseo_admin_pages->textinput( 'title-' . $name, __( 'Title template', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-' . $name, __( 'Meta description template', 'wordpress-seo' ), '', 'metadesc' );
$name = $pt->name;
echo '<strong id="' . esc_attr( $name ) . '">' . esc_html( ucfirst( $pt->labels->name ) ) . '</strong><br/>';
if ( $warn === true ) {
echo '<h4 class="error-message">' . __( 'Take note:', 'wordpress-seo' ) . '</h4>';
echo '<p class="error-message">' . __( 'As you are redirecting attachment URLs to parent post URLs, these settings will currently only have an effect on <strong>unattached</strong> media items!', 'wordpress-seo' ) . '</p>';
echo '<p class="error-message">' . sprintf( __( 'So remember: If you change the %sattachment redirection setting%s in the future, the below settings will take effect for *all* media items.', 'wordpress-seo' ), '<a href="' . esc_url( admin_url( 'admin.php?page=wpseo_permalinks' ) ) . '">', '</a>' ) . '</p>';
}
$yform->textinput( 'title-' . $name, __( 'Title template', 'wordpress-seo' ), 'template posttype-template' );
$yform->textarea( 'metadesc-' . $name, __( 'Meta description template', 'wordpress-seo' ), array( 'class' => 'template posttype-template' ) );
if ( $options['usemetakeywords'] === true ) {
$yform->textinput( 'metakey-' . $name, __( 'Meta keywords template', 'wordpress-seo' ) );
}
$yform->checkbox( 'noindex-' . $name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
$yform->checkbox( 'showdate-' . $name, __( 'Show date in snippet preview?', 'wordpress-seo' ), __( 'Date in Snippet Preview', 'wordpress-seo' ) );
$yform->checkbox( 'hideeditbox-' . $name, __( 'Hide', 'wordpress-seo' ), __( 'WordPress SEO Meta Box', 'wordpress-seo' ) );
/**
* Allow adding a custom checkboxes to the admin meta page - Post Types tab
* @api WPSEO_Admin_Pages $yform The WPSEO_Admin_Pages object
* @api String $name The post type name
*/
do_action( 'wpseo_admin_page_meta_post_types', $yform, $name );
echo '<br/><br/>';
if ( $warn === true ) {
echo '</div>';
}
unset( $warn );
}
unset( $pt );
}
unset( $post_types );
$post_types = get_post_types( array( '_builtin' => false, 'has_archive' => true ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
echo '<h2>' . __( 'Custom Post Type Archives', 'wordpress-seo' ) . '</h2>';
echo '<p>' . __( 'Note: instead of templates these are the actual titles and meta descriptions for these custom post type archive pages.', 'wordpress-seo' ) . '</p>';
foreach ( $post_types as $pt ) {
$name = $pt->name;
echo '<strong>' . esc_html( ucfirst( $pt->labels->name ) ) . '</strong><br/>';
$yform->textinput( 'title-ptarchive-' . $name, __( 'Title', 'wordpress-seo' ), 'template posttype-template' );
$yform->textarea( 'metadesc-ptarchive-' . $name, __( 'Meta description', 'wordpress-seo' ), array( 'class' => 'template posttype-template' ) );
if ( $options['usemetakeywords'] === true ) {
$yform->textinput( 'metakey-ptarchive-' . $name, __( 'Meta keywords', 'wordpress-seo' ) );
}
if ( $options['breadcrumbs-enable'] === true ) {
$yform->textinput( 'bctitle-ptarchive-' . $name, __( 'Breadcrumbs title', 'wordpress-seo' ) );
}
$yform->checkbox( 'noindex-ptarchive-' . $name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
echo '<br/><br/>';
}
unset( $pt );
}
unset( $post_types );
?>
</div>
<div id="taxonomies" class="wpseotab">
<?php
$taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
foreach ( $taxonomies as $tax ) {
echo '<strong>' . esc_html( ucfirst( $tax->labels->name ) ) . '</strong><br/>';
$yform->textinput( 'title-tax-' . $tax->name, __( 'Title template', 'wordpress-seo' ), 'template taxonomy-template' );
$yform->textarea( 'metadesc-tax-' . $tax->name, __( 'Meta description template', 'wordpress-seo' ), array( 'class' => 'template taxonomy-template' ) );
if ( $options['usemetakeywords'] === true ) {
$yform->textinput( 'metakey-tax-' . $tax->name, __( 'Meta keywords template', 'wordpress-seo' ) );
}
$yform->checkbox( 'noindex-tax-' . $tax->name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
$yform->checkbox( 'hideeditbox-tax-' . $tax->name, __( 'Hide', 'wordpress-seo' ), __( 'WordPress SEO Meta Box', 'wordpress-seo' ) );
echo '<br/><br/>';
}
unset( $tax );
}
unset( $taxonomies );
?>
</div>
<div id="archives" class="wpseotab">
<?php
echo '<strong>' . __( 'Author Archives', 'wordpress-seo' ) . '</strong><br/>';
$yform->textinput( 'title-author-wpseo', __( 'Title template', 'wordpress-seo' ), 'template author-template' );
$yform->textarea( 'metadesc-author-wpseo', __( 'Meta description template', 'wordpress-seo' ), array( 'class' => 'template author-template' ) );
if ( $options['usemetakeywords'] === true ) {
echo $wpseo_admin_pages->textinput( 'metakey-' . $name, __( 'Meta keywords template', 'wordpress-seo' ) );
$yform->textinput( 'metakey-author-wpseo', __( 'Meta keywords template', 'wordpress-seo' ) );
}
echo $wpseo_admin_pages->checkbox( 'noindex-' . $name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'showdate-' . $name, __( 'Show date in snippet preview?', 'wordpress-seo' ), __( 'Date in Snippet Preview', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'hideeditbox-' . $name, __( 'Hide', 'wordpress-seo' ), __( 'WordPress SEO Meta Box', 'wordpress-seo' ) );
/**
* Allow adding a custom checkboxes to the admin meta page - Post Types tab
* @api WPSEO_Admin_Pages $wpseo_admin_pages The WPSEO_Admin_Pages object
* @api String $name The post type name
*/
do_action( 'wpseo_admin_page_meta_post_types', $wpseo_admin_pages, $name );
$yform->checkbox( 'noindex-author-wpseo', '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
$yform->checkbox( 'disable-author', __( 'Disable the author archives', 'wordpress-seo' ), '' );
echo '<p class="desc label">' . __( 'If you\'re running a one author blog, the author archive will always look exactly the same as your homepage. And even though you may not link to it, others might, to do you harm. Disabling them here will make sure any link to those archives will be 301 redirected to the homepage.', 'wordpress-seo' ) . '</p>';
echo '<br/>';
if ( $warn === true ) {
echo '</div>';
}
unset( $warn );
}
unset( $pt );
}
unset( $post_types );
$post_types = get_post_types( array( 'public' => true, '_builtin' => false ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
echo '<h2>' . __( 'Custom Post Type Archives', 'wordpress-seo' ) . '</h2>';
echo '<p>' . __( 'Note: instead of templates these are the actual titles and meta descriptions for these custom post type archive pages.', 'wordpress-seo' ) . '</p>';
foreach ( $post_types as $pt ) {
if ( ! $pt->has_archive ) {
continue;
}
$name = $pt->name;
echo '<h4>' . esc_html( ucfirst( $pt->labels->name ) ) . '</h4>';
echo $wpseo_admin_pages->textinput( 'title-ptarchive-' . $name, __( 'Title', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-ptarchive-' . $name, __( 'Meta description', 'wordpress-seo' ), '', 'metadesc' );
if ( $options['usemetakeywords'] === true ) {
echo $wpseo_admin_pages->textinput( 'metakey-ptarchive-' . $name, __( 'Meta keywords', 'wordpress-seo' ) );
}
if ( $options['breadcrumbs-enable'] === true ) {
echo $wpseo_admin_pages->textinput( 'bctitle-ptarchive-' . $name, __( 'Breadcrumbs title', 'wordpress-seo' ) );
}
echo $wpseo_admin_pages->checkbox( 'noindex-ptarchive-' . $name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
}
unset( $pt );
}
unset( $post_types );
?>
</div>
<div id="taxonomies" class="wpseotab">
<?php
$taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
foreach ( $taxonomies as $tax ) {
echo '<h4>' . esc_html( ucfirst( $tax->labels->name ) ). '</h4>';
echo $wpseo_admin_pages->textinput( 'title-tax-' . $tax->name, __( 'Title template', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-tax-' . $tax->name, __( 'Meta description template', 'wordpress-seo' ), '', 'metadesc' );
if ( $options['usemetakeywords'] === true ) {
echo $wpseo_admin_pages->textinput( 'metakey-tax-' . $tax->name, __( 'Meta keywords template', 'wordpress-seo' ) );
}
echo $wpseo_admin_pages->checkbox( 'noindex-tax-' . $tax->name, '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'hideeditbox-tax-' . $tax->name, __( 'Hide', 'wordpress-seo' ), __( 'WordPress SEO Meta Box', 'wordpress-seo' ) );
echo '<strong>' . __( 'Date Archives', 'wordpress-seo' ) . '</strong><br/>';
$yform->textinput( 'title-archive-wpseo', __( 'Title template', 'wordpress-seo' ), 'template date-template' );
$yform->textarea( 'metadesc-archive-wpseo', __( 'Meta description template', 'wordpress-seo' ), array( 'class' => 'template date-template' ) );
echo '<br/>';
}
unset( $tax );
}
unset( $taxonomies );
$yform->checkbox( 'noindex-archive-wpseo', '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
$yform->checkbox( 'disable-date', __( 'Disable the date-based archives', 'wordpress-seo' ), '' );
echo '<p class="desc label">' . __( 'For the date based archives, the same applies: they probably look a lot like your homepage, and could thus be seen as duplicate content.', 'wordpress-seo' ) . '</p>';
?>
</div>
<div id="archives" class="wpseotab">
<?php
echo '<h4>' . __( 'Author Archives', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->textinput( 'title-author-wpseo', __( 'Title template', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-author-wpseo', __( 'Meta description template', 'wordpress-seo' ), '', 'metadesc' );
if ( $options['usemetakeywords'] === true ) {
echo $wpseo_admin_pages->textinput( 'metakey-author-wpseo', __( 'Meta keywords template', 'wordpress-seo' ) );
}
echo $wpseo_admin_pages->checkbox( 'noindex-author-wpseo', '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'disable-author', __( 'Disable the author archives', 'wordpress-seo' ), '' );
echo '<p class="desc label">' . __( 'If you\'re running a one author blog, the author archive will always look exactly the same as your homepage. And even though you may not link to it, others might, to do you harm. Disabling them here will make sure any link to those archives will be 301 redirected to the homepage.', 'wordpress-seo' ) . '</p>';
echo '<br/>';
echo '<h4>' . __( 'Date Archives', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->textinput( 'title-archive-wpseo', __( 'Title template', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textarea( 'metadesc-archive-wpseo', __( 'Meta description template', 'wordpress-seo' ), '', 'metadesc' );
echo '<br/>';
echo $wpseo_admin_pages->checkbox( 'noindex-archive-wpseo', '<code>noindex, follow</code>', __( 'Meta Robots', 'wordpress-seo' ) );
echo $wpseo_admin_pages->checkbox( 'disable-date', __( 'Disable the date-based archives', 'wordpress-seo' ), '' );
echo '<p class="desc label">' . __( 'For the date based archives, the same applies: they probably look a lot like your homepage, and could thus be seen as duplicate content.', 'wordpress-seo' ) . '</p>';
echo '<h2>' . __( 'Special Pages', 'wordpress-seo' ) . '</h2>';
echo '<p>' . __( 'These pages will be noindex, followed by default, so they will never show up in search results.', 'wordpress-seo' ) . '</p>';
echo '<p><strong>' . __( 'Search pages', 'wordpress-seo' ) . '</strong><br/>';
$yform->textinput( 'title-search-wpseo', __( 'Title template', 'wordpress-seo' ), 'template search-template' );
echo '</p>';
echo '<p><strong>' . __( '404 pages', 'wordpress-seo' ) . '</strong><br/>';
$yform->textinput( 'title-404-wpseo', __( 'Title template', 'wordpress-seo' ), 'template error404-template' );
echo '</p>';
echo '<br class="clear"/>';
?>
</div>
<div id="other" class="wpseotab">
<strong><?php _e( 'Sitewide <code>meta</code> settings', 'wordpress-seo' ); ?></strong><br/>
<br/>
<?php
$yform->checkbox( 'noindex-subpages-wpseo', __( 'Noindex subpages of archives', 'wordpress-seo' ) );
echo '<p class="desc">', __( 'If you want to prevent /page/2/ and further of any archive to show up in the search results, enable this.', 'wordpress-seo' ), '</p>';
echo '<h2>' . __( 'Special Pages', 'wordpress-seo' ) . '</h2>';
echo '<p>' . __( 'These pages will be noindex, followed by default, so they will never show up in search results.', 'wordpress-seo' ) . '</p>';
echo '<h4>' . __( 'Search pages', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->textinput( 'title-search-wpseo', __( 'Title template', 'wordpress-seo' ) );
echo '<h4>' . __( '404 pages', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->textinput( 'title-404-wpseo', __( 'Title template', 'wordpress-seo' ) );
echo '<br class="clear"/>';
?>
</div>
<div id="template_help" class="wpseotab">
<?php
$yform->checkbox( 'usemetakeywords', __( 'Use <code>meta</code> keywords tag?', 'wordpress-seo' ) );
echo '<p class="desc">', __( 'I don\'t know why you\'d want to use meta keywords, but if you want to, check this box.', 'wordpress-seo' ), '</p>';
echo '<h2>' . __( 'Variables', 'wordpress-seo' ) . '</h2>';
echo '</div>';
echo '</div>';
$wpseo_admin_pages->admin_footer();
$yform->checkbox( 'noodp', __( 'Add <code>noodp</code> meta robots tag sitewide', 'wordpress-seo' ) );
echo '<p class="desc">', __( 'Prevents search engines from using the DMOZ description for pages from this site in the search results.', 'wordpress-seo' ), '</p>';
$yform->checkbox( 'noydir', __( 'Add <code>noydir</code> meta robots tag sitewide', 'wordpress-seo' ) );
echo '<p class="desc">', __( 'Prevents search engines from using the Yahoo! directory description for pages from this site in the search results.', 'wordpress-seo' ), '</p>';
?>
</div>
</div>
<?php
$yform->admin_footer();
@@ -1,6 +1,6 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,7 +9,7 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$yform = Yoast_Form::get_instance();
$options = get_site_option( 'wpseo_ms' );
@@ -19,6 +19,7 @@ if ( isset( $_POST['wpseo_submit'] ) ) {
foreach ( array( 'access', 'defaultblog' ) as $opt ) {
$options[ $opt ] = $_POST['wpseo_ms'][ $opt ];
}
unset( $opt );
WPSEO_Options::update_site_option( 'wpseo_ms', $options );
add_settings_error( 'wpseo_ms', 'settings_updated', __( 'Settings Updated.', 'wordpress-seo' ), 'updated' );
}
@@ -26,7 +27,7 @@ if ( isset( $_POST['wpseo_submit'] ) ) {
if ( isset( $_POST['wpseo_restore_blog'] ) ) {
check_admin_referer( 'wpseo-network-restore' );
if ( isset( $_POST['wpseo_ms']['restoreblog'] ) && is_numeric( $_POST['wpseo_ms']['restoreblog'] ) ) {
$restoreblog = (int) WPSEO_Option::validate_int( $_POST['wpseo_ms']['restoreblog'] );
$restoreblog = (int) WPSEO_Utils::validate_int( $_POST['wpseo_ms']['restoreblog'] );
$blog = get_blog_details( $restoreblog );
if ( $blog ) {
@@ -36,7 +37,7 @@ if ( isset( $_POST['wpseo_restore_blog'] ) ) {
else {
add_settings_error( 'wpseo_ms', 'settings_updated', sprintf( __( 'Blog %s not found.', 'wordpress-seo' ), esc_html( $restoreblog ) ), 'error' );
}
unset( $restoreblog );
unset( $restoreblog, $blog );
}
}
@@ -80,15 +81,14 @@ else {
unset( $sites );
}
$yform->admin_header( false, 'wpseo_ms' );
$wpseo_admin_pages->admin_header( false, 'wpseo-network-settings', 'wpseo_ms' );
$content = '<form method="post" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
$content .= wp_nonce_field( 'wpseo-network-settings', '_wpnonce', true, false );
echo '<h2>', __( 'MultiSite Settings', 'wordpress-seo' ), '</h2>';
echo '<form method="post" accept-charset="', esc_attr( get_bloginfo( 'charset' ) ), '">';
wp_nonce_field( 'wpseo-network-settings', '_wpnonce', true, true );
/* @internal Important: Make sure the options added to the array here are in line with the options set in the WPSEO_Option_MS::$allowed_access_options property */
$content .= $wpseo_admin_pages->select(
$yform->select(
'access',
__( 'Who should have access to the WordPress SEO settings', 'wordpress-seo' ),
array(
@@ -99,34 +99,32 @@ $content .= $wpseo_admin_pages->select(
);
if ( $use_dropdown === true ) {
$content .= $wpseo_admin_pages->select(
$yform->select(
'defaultblog',
__( 'New sites in the network inherit their SEO settings from this site', 'wordpress-seo' ),
$dropdown_input,
'wpseo_ms'
);
$content .= '<p>' . __( 'Choose the site whose settings you want to use as default for all sites that are added to your network. If you choose \'None\', the normal plugin defaults will be used.', 'wordpress-seo' ) . '</p>';
echo '<p>' . __( 'Choose the site whose settings you want to use as default for all sites that are added to your network. If you choose \'None\', the normal plugin defaults will be used.', 'wordpress-seo' ) . '</p>';
}
else {
$content .= $wpseo_admin_pages->textinput( 'defaultblog', __( 'New sites in the network inherit their SEO settings from this site', 'wordpress-seo' ), 'wpseo_ms' );
$content .= '<p>' . sprintf( __( 'Enter the %sSite ID%s for the site whose settings you want to use as default for all sites that are added to your network. Leave empty for none (i.e. the normal plugin defaults will be used).', 'wordpress-seo' ), '<a href="' . esc_url( network_admin_url( 'sites.php' ) ) . '">', '</a>' ) . '</p>';
$yform->textinput( 'defaultblog', __( 'New sites in the network inherit their SEO settings from this site', 'wordpress-seo' ), 'wpseo_ms' );
echo '<p>' . sprintf( __( 'Enter the %sSite ID%s for the site whose settings you want to use as default for all sites that are added to your network. Leave empty for none (i.e. the normal plugin defaults will be used).', 'wordpress-seo' ), '<a href="' . esc_url( network_admin_url( 'sites.php' ) ) . '">', '</a>' ) . '</p>';
}
$content .= '<p><strong>' . __( 'Take note:', 'wordpress-seo' ) . '</strong> ' . __( 'Privacy sensitive (FB admins and such), theme specific (title rewrite) and a few very site specific settings will not be imported to new blogs.', 'wordpress-seo' ) . '</p>';
echo '<p><strong>' . __( 'Take note:', 'wordpress-seo' ) . '</strong> ' . __( 'Privacy sensitive (FB admins and such), theme specific (title rewrite) and a few very site specific settings will not be imported to new blogs.', 'wordpress-seo' ) . '</p>';
$content .= '<input type="submit" name="wpseo_submit" class="button-primary" value="' . __( 'Save MultiSite Settings', 'wordpress-seo' ) . '"/>';
$content .= '</form>';
echo '<input type="submit" name="wpseo_submit" class="button-primary" value="' . __( 'Save MultiSite Settings', 'wordpress-seo' ) . '"/>';
echo '</form>';
$wpseo_admin_pages->postbox( 'wpseo_network_settings', __( 'MultiSite Settings', 'wordpress-seo' ), $content );
$content = '<form method="post" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
$content .= wp_nonce_field( 'wpseo-network-restore', '_wpnonce', true, false );
$content .= '<p>' . __( 'Using this form you can reset a site to the default SEO settings.', 'wordpress-seo' ) . '</p>';
echo '<h2>' . __( 'Restore site to default settings', 'wordpress-seo' ) . '</h2>';
echo '<form method="post" accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
wp_nonce_field( 'wpseo-network-restore', '_wpnonce', true, true );
echo '<p>' . __( 'Using this form you can reset a site to the default SEO settings.', 'wordpress-seo' ) . '</p>';
if ( $use_dropdown === true ) {
unset( $dropdown_input['-'] );
$content .= $wpseo_admin_pages->select(
$yform->select(
'restoreblog',
__( 'Site ID', 'wordpress-seo' ),
$dropdown_input,
@@ -134,12 +132,11 @@ if ( $use_dropdown === true ) {
);
}
else {
$content .= $wpseo_admin_pages->textinput( 'restoreblog', __( 'Blog ID', 'wordpress-seo' ), 'wpseo_ms' );
$yform->textinput( 'restoreblog', __( 'Blog ID', 'wordpress-seo' ), 'wpseo_ms' );
}
$content .= '<input type="submit" name="wpseo_restore_blog" value="' . __( 'Restore site to defaults', 'wordpress-seo' ) . '" class="button"/>';
$content .= '</form>';
echo '<input type="submit" name="wpseo_restore_blog" value="' . __( 'Restore site to defaults', 'wordpress-seo' ) . '" class="button"/>';
echo '</form>';
$wpseo_admin_pages->postbox( 'wpseo-network-restore', __( 'Restore site to default settings', 'wordpress-seo' ), $content );
$wpseo_admin_pages->admin_footer( false );
$yform->admin_footer( false );
@@ -1,59 +0,0 @@
<?php
/**
* @package Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
global $wpseo_admin_pages;
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_permalinks' ), 'wpseo_permalinks' );
$options = get_option( 'wpseo_permalinks' );
$content = '';
$content .= $wpseo_admin_pages->checkbox( 'stripcategorybase', __( 'Strip the category base (usually <code>/category/</code>) from the category URL.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . sprintf( __( 'We suggest using %1$sFV Top Level Categories%2$s, if you insist on keeping this but do know that the feature is very error prone and not <em>that</em> important for your SEO.', 'wordpress-seo' ), '<a href="https://wordpress.org/plugins/fv-top-level-cats/">', '</a>' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'trailingslash', __( 'Enforce a trailing slash on all category and tag URL\'s', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'If you choose a permalink for your posts with <code>.html</code>, or anything else but a / on the end, this will force WordPress to add a trailing slash to non-post pages nonetheless.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'cleanslugs', __( 'Remove stop words from slugs.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'This helps you to create cleaner URLs by automatically removing the stopwords from them.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'redirectattachment', __( 'Redirect attachment URL\'s to parent post URL.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'Attachments to posts are stored in the database as posts, this means they\'re accessible under their own URL\'s if you do not redirect them, enabling this will redirect them to the post they were attached to.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'cleanreplytocom', __( 'Remove the <code>?replytocom</code> variables.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'This prevents threaded replies from working when the user has JavaScript disabled, but on a large site can mean a <em>huge</em> improvement in crawl efficiency for search engines when you have a lot of comments.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'cleanpermalinks', __( 'Redirect ugly URL\'s to clean permalinks. (Not recommended in many cases!)', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'People make mistakes in their links towards you sometimes, or unwanted parameters are added to the end of your URLs, this allows you to redirect them all away. Please note that while this is a feature that is actively maintained, it is known to break several plugins, and should for that reason be the first feature you disable when you encounter issues after installing this plugin.', 'wordpress-seo' ) . '</p>';
$wpseo_admin_pages->postbox( 'permalinks', __( 'Permalink Settings', 'wordpress-seo' ), $content );
/* @internal Important: Make sure the options added to the array here are in line with the options set in the WPSEO_Option_Permalinks::$force_transport_options property */
$content = $wpseo_admin_pages->select( 'force_transport', __( 'Force Transport', 'wordpress-seo' ), array( 'default' => __( 'Leave default', 'wordpress-seo' ), 'http' => __( 'Force http', 'wordpress-seo' ), 'https' => __( 'Force https', 'wordpress-seo' ) ) );
$content .= '<p class="desc label">' . __( 'Force the canonical to either http or https, when your blog runs under both.', 'wordpress-seo' ) . '</p>';
$wpseo_admin_pages->postbox( 'canonical', __( 'Canonical Settings', 'wordpress-seo' ), $content );
$content = $wpseo_admin_pages->checkbox( 'cleanpermalink-googlesitesearch', __( 'Prevent cleaning out Google Site Search URL\'s.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'Google Site Search URL\'s look weird, and ugly, but if you\'re using Google Site Search, you probably do not want them cleaned out.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'cleanpermalink-googlecampaign', __( 'Prevent cleaning out Google Analytics Campaign & Google AdWords Parameters.', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'If you use Google Analytics campaign parameters starting with <code>?utm_</code>, check this box. You shouldn\'t use these btw, you should instead use the hash tagged version instead.', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->textinput( 'cleanpermalink-extravars', __( 'Other variables not to clean', 'wordpress-seo' ) );
$content .= '<p class="desc">' . __( 'You might have extra variables you want to prevent from cleaning out, add them here, comma separated.', 'wordpress-seo' ) . '</p>';
$wpseo_admin_pages->postbox( 'cleanpermalinksdiv', __( 'Clean Permalink Settings', 'wordpress-seo' ), $content );
$wpseo_admin_pages->admin_footer();
@@ -1,44 +0,0 @@
<?php
/**
* @package Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
global $wpseo_admin_pages;
$options = WPSEO_Options::get_all();
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_rss' ), 'wpseo_rss' );
$content = '<p>' . __( "This feature is used to automatically add content to your RSS, more specifically, it's meant to add links back to your blog and your blog posts, so dumb scrapers will automatically add these links too, helping search engines identify you as the original source of the content.", 'wordpress-seo' ) . '</p>';
$rows = array();
$rows[] = array(
'id' => 'rssbefore',
'label' => __( 'Content to put before each post in the feed', 'wordpress-seo' ),
'desc' => __( '(HTML allowed)', 'wordpress-seo' ),
'content' => '<textarea cols="50" rows="5" id="rssbefore" name="wpseo_rss[rssbefore]">' . esc_textarea( $options['rssbefore'] ) . '</textarea>',
);
$rows[] = array(
'id' => 'rssafter',
'label' => __( 'Content to put after each post in the feed', 'wordpress-seo' ),
'desc' => __( '(HTML allowed)', 'wordpress-seo' ),
'content' => '<textarea cols="50" rows="5" id="rssafter" name="wpseo_rss[rssafter]">' . esc_textarea( $options['rssafter'] ) . '</textarea>',
);
$rows[] = array(
'label' => __( 'Explanation', 'wordpress-seo' ),
'content' => '<p>' . __( 'You can use the following variables within the content, they will be replaced by the value on the right.', 'wordpress-seo' ) . '</p>' .
'<table>' .
'<tr><th><strong>%%AUTHORLINK%%</strong></th><td>' . __( 'A link to the archive for the post author, with the authors name as anchor text.', 'wordpress-seo' ) . '</td></tr>' .
'<tr><th><strong>%%POSTLINK%%</strong></th><td>' . __( 'A link to the post, with the title as anchor text.', 'wordpress-seo' ) . '</td></tr>' .
'<tr><th><strong>%%BLOGLINK%%</strong></th><td>' . __( "A link to your site, with your site's name as anchor text.", 'wordpress-seo' ) . '</td></tr>' .
'<tr><th><strong>%%BLOGDESCLINK%%</strong></th><td>' . __( "A link to your site, with your site's name and description as anchor text.", 'wordpress-seo' ) . '</td></tr>' .
'</table>'
);
$wpseo_admin_pages->postbox( 'rssfootercontent', __( 'Content of your RSS Feed', 'wordpress-seo' ), $content . $wpseo_admin_pages->form_table( $rows ) );
$wpseo_admin_pages->admin_footer();
@@ -1,6 +1,6 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,225 +9,113 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$yform = Yoast_Form::get_instance();
$fbconnect = '
<p><strong>' . esc_html__( 'Facebook Insights and Admins', 'wordpress-seo' ) . '</strong><br>
' . sprintf( esc_html__( 'To be able to access your %sFacebook Insights%s for your site, you need to specify a Facebook Admin. This can be a user, but if you have an app for your site, you could use that. For most people a user will be "good enough" though.', 'wordpress-seo' ), '<a href="https://www.facebook.com/insights">', '</a>' ) . '</p>';
$fbbuttons = array();
$social_facebook = new Yoast_Social_Facebook( );
$clearall = false;
$options = get_option( 'wpseo_social' );
if ( isset( $_GET['delfbadmin'] ) ) {
if ( wp_verify_nonce( $_GET['nonce'], 'delfbadmin' ) != 1 ) {
die( 'I don\'t think that\'s really nice of you!.' );
}
$id = sanitize_text_field( $_GET['delfbadmin'] );
if ( isset( $options['fb_admins'][ $id ] ) ) {
$fbadmin = $options['fb_admins'][ $id ]['name'];
unset( $options['fb_admins'][ $id ] );
update_option( 'wpseo_social', $options );
add_settings_error( 'yoast_wpseo_social_options', 'success', sprintf( __( 'Successfully removed admin %s', 'wordpress-seo' ), $fbadmin ), 'updated' );
unset( $fbadmin );
}
unset( $id );
// Clean up the referrer url for later use
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'nonce', 'delfbadmin' ), sanitize_text_field( $_SERVER['REQUEST_URI'] ) );
}
}
elseif ( isset( $_GET['fbclearall'] ) ) {
if ( wp_verify_nonce( $_GET['nonce'], 'fbclearall' ) != 1 ) {
die( "I don't think that's really nice of you!." );
}
// Reset to defaults, don't unset as otherwise the old values will be retained
$options['fb_admins'] = WPSEO_Options::get_default( 'wpseo_social', 'fb_admins' );
$options['fbapps'] = WPSEO_Options::get_default( 'wpseo_social', 'fbapps' );
$options['fbadminapp'] = WPSEO_Options::get_default( 'wpseo_social', 'fbadminapp' );
update_option( 'wpseo_social', $options );
add_settings_error( 'yoast_wpseo_social_options', 'success', __( 'Successfully cleared all Facebook Data', 'wordpress-seo' ), 'updated' );
// Clean up the referrer url for later use
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'nonce', 'fbclearall' ), sanitize_text_field( $_SERVER['REQUEST_URI'] ) );
}
}
elseif ( isset( $_GET['key'] ) ) {
if ( $_GET['key'] === $options['fbconnectkey'] ) {
if ( isset( $_GET['userid'] ) ) {
$user_id = sanitize_text_field( $_GET['userid'] );
if ( ! isset( $options['fb_admins'][ $user_id ] ) ) {
$options['fb_admins'][ $user_id ]['name'] = sanitize_text_field( urldecode( $_GET['userrealname'] ) );
$options['fb_admins'][ $user_id ]['link'] = sanitize_text_field( urldecode( $_GET['link'] ) );
update_option( 'wpseo_social', $options );
add_settings_error( 'yoast_wpseo_social_options', 'success', sprintf( __( 'Successfully added %s as a Facebook Admin!', 'wordpress-seo' ), '<a href="' . esc_url( $options['fb_admins'][ $user_id ]['link'] ) . '">' . esc_html( $options['fb_admins'][ $user_id ]['name'] ) . '</a>' ), 'updated' );
}
else {
add_settings_error( 'yoast_wpseo_social_options', 'error', sprintf( __( '%s already exists as a Facebook Admin.', 'wordpress-seo' ), '<a href="' . esc_url( $options['fb_admins'][ $user_id ]['link'] ) . '">' . esc_html( $options['fb_admins'][ $user_id ]['name'] ) . '</a>' ), 'error' );
}
unset( $user_id );
}
elseif ( isset( $_GET['apps'] ) ) {
$apps = json_decode( stripslashes( $_GET['apps'] ), true );
if ( is_array( $apps ) && $apps !== array() ) {
$options['fbapps'] = array( '0' => __( 'Do not use a Facebook App as Admin', 'wordpress-seo' ) );
foreach ( $apps as $app ) {
$options['fbapps'][ $app['app_id'] ] = $app['display_name'];
}
update_option( 'wpseo_social', $options );
add_settings_error( 'yoast_wpseo_social_options', 'success', __( 'Successfully retrieved your apps from Facebook, now select an app to use as admin.', 'wordpress-seo' ), 'updated' );
}
else {
add_settings_error( 'yoast_wpseo_social_options', 'error', __( 'Failed to retrieve your apps from Facebook.', 'wordpress-seo' ), 'error' );
}
unset( $apps, $app );
}
}
// Clean up the referrer url for later use
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'key', 'userid', 'userrealname', 'link', 'apps' ), sanitize_text_field( $_SERVER['REQUEST_URI'] ) );
}
}
// Refresh option after updates
$options = get_option( 'wpseo_social' );
if ( is_array( $options['fb_admins'] ) && $options['fb_admins'] !== array() ) {
$clearall = true;
}
if ( is_array( $options['fbapps'] ) && $options['fbapps'] !== array() ) {
$clearall = true;
}
$app_button_text = __( 'Use a Facebook App as Admin', 'wordpress-seo' );
if ( is_array( $options['fbapps'] ) && $options['fbapps'] !== array() ) {
// @todo [JRF => whomever] use WPSEO_Admin_Pages->select() method ?
$fbconnect .= '
<p>' . __( 'Select an app to use as Facebook admin:', 'wordpress-seo' ) . '</p>
<select name="wpseo_social[fbadminapp]" id="fbadminapp">';
foreach ( $options['fbapps'] as $id => $app ) {
$fbconnect .= '
<option value="' . esc_attr( $id ) . '" ' . selected( $id, $options['fbadminapp'], false ) . '>' . esc_attr( $app ) . '</option>';
}
$fbconnect .= '
</select>
<div class="clear"></div><br/>';
$app_button_text = __( 'Update Facebook Apps', 'wordpress-seo' );
}
if ( $options['fbadminapp'] == 0 ) {
$button_text = __( 'Add Facebook Admin', 'wordpress-seo' );
$primary = true;
if ( is_array( $options['fb_admins'] ) && $options['fb_admins'] !== array() ) {
$fbconnect .= '
<p>' . __( 'Currently connected Facebook admins:', 'wordpress-seo' ) . '</p>
<ul>';
$nonce = wp_create_nonce( 'delfbadmin' );
foreach ( $options['fb_admins'] as $admin_id => $admin ) {
$admin_id = esc_attr( $admin_id );
$fbconnect .= '
<li><a href="' . esc_url( $admin['link'] ) . '">' . esc_html( $admin['name'] ) . '</a> - <strong><a href="' . esc_url( add_query_arg( array( 'delfbadmin' => $admin_id, 'nonce' => $nonce ), admin_url( 'admin.php?page=wpseo_social' ) ) ) . '">X</a></strong></li>';
}
$fbconnect .= '
</ul>';
$button_text = __( 'Add Another Facebook Admin', 'wordpress-seo' );
$primary = false;
}
$but_primary = '';
if ( $primary ) {
$but_primary = '-primary';
}
$fbbuttons[] = '
<a class="button' . esc_attr( $but_primary ) . '" href="' . esc_url( 'https://yoast.com/fb-connect/?key=' . urlencode( $options['fbconnectkey'] ) . '&redirect=' . urlencode( admin_url( 'admin.php?page=wpseo_social' ) ) ) . '">' . $button_text . '</a>';
}
$fbbuttons[] = '
<a class="button" href="' . esc_url( 'https://yoast.com/fb-connect/?key=' . urlencode( $options['fbconnectkey'] ) . '&type=app&redirect=' . urlencode( admin_url( 'admin.php?page=wpseo_social' ) ) ) . '">' . esc_html( $app_button_text ) . '</a>';
if ( $clearall ) {
$fbbuttons[] = '
<a class="button" href="' . esc_url( add_query_arg( array( 'nonce' => wp_create_nonce( 'fbclearall' ), 'fbclearall' => 'true' ), admin_url( 'admin.php?page=wpseo_social' ) ) ) . '">' . __( 'Clear all Facebook Data', 'wordpress-seo' ) . '</a> ';
}
if ( is_array( $fbbuttons ) && $fbbuttons !== array() ) {
$fbconnect .= '
<p class="fb-buttons">' . implode( '', $fbbuttons ) . '</p>';
}
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_social' ), 'wpseo_social' );
$yform->admin_header( true, 'wpseo_social' );
?>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab nav-tab-active" id="facebook-tab" href="#top#facebook"><?php _e( 'Facebook', 'wordpress-seo' );?></a>
<a class="nav-tab" id="twitterbox-tab" href="#top#twitterbox"><?php _e( 'Twitter', 'wordpress-seo' );?></a>
<a class="nav-tab" id="google-tab" href="#top#google"><?php _e( 'Google+', 'wordpress-seo' );?></a>
</h2>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="accounts-tab" href="#top#accounts"><?php _e( 'Accounts', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="facebook-tab" href="#top#facebook"><span class="dashicons dashicons-facebook-alt"></span> <?php _e( 'Facebook', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="twitterbox-tab" href="#top#twitterbox"><span class="dashicons dashicons-twitter"></span> <?php _e( 'Twitter', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="pinterest-tab" href="#top#pinterest"><?php _e( 'Pinterest', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="google-tab" href="#top#google"><span class="dashicons dashicons-googleplus"></span> <?php _e( 'Google+', 'wordpress-seo' ); ?></a>
</h2>
<div id="accounts" class="wpseotab">
<p>
<?php _e( 'To inform Google about your social profiles, we need to know their URLs.', 'wordpress-seo' ); ?>
<?php _e( 'For each, pick the main account associated with this site and please enter them below:', 'wordpress-seo' ); ?>
</p>
<?php
$yform->textinput( 'facebook_site', __( 'Facebook Page URL', 'wordpress-seo' ) );
$yform->textinput( 'twitter_site', __( 'Twitter Username', 'wordpress-seo' ) );
$yform->textinput( 'instagram_url', __( 'Instagram URL', 'wordpress-seo' ) );
$yform->textinput( 'linkedin_url', __( 'LinkedIn URL', 'wordpress-seo' ) );
$yform->textinput( 'myspace_url', __( 'MySpace URL', 'wordpress-seo' ) );
$yform->textinput( 'pinterest_url', __( 'Pinterest URL', 'wordpress-seo' ) );
$yform->textinput( 'youtube_url', __( 'YouTube URL', 'wordpress-seo' ) );
$yform->textinput( 'google_plus_url', __( 'Google+ URL', 'wordpress-seo' ) );
do_action( 'wpseo_admin_other_section' );
?>
</div>
<div id="facebook" class="wpseotab">
<p>
<?php $yform->checkbox( 'opengraph', __( 'Add Open Graph meta data', 'wordpress-seo' ) ); ?>
</p>
<p class="desc">
<?php _e( 'Add Open Graph meta data to your site\'s <code>&lt;head&gt;</code> section. You can specify some of the ID\'s that are sometimes needed below:', 'wordpress-seo' ); ?>
</p>
<?php
$social_facebook->show_form();
<div id="facebook" class="wpseotab">
<?php
echo '<p>';
echo $wpseo_admin_pages->checkbox( 'opengraph', __( 'Add Open Graph meta data', 'wordpress-seo' ) );
echo '</p>';
echo'<p class="desc">' . __( 'Add Open Graph meta data to your site\'s <code>&lt;head&gt;</code> section. You can specify some of the ID\'s that are sometimes needed below:', 'wordpress-seo' ) . '</p>';
echo $fbconnect;
echo $wpseo_admin_pages->textinput( 'facebook_site', __( 'Facebook Page URL', 'wordpress-seo' ) );
if ( 'posts' == get_option( 'show_on_front' ) ) {
echo '<h4>' . esc_html__( 'Frontpage settings', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->media_input( 'og_frontpage_image', __( 'Image URL', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textinput( 'og_frontpage_title', __( 'Title', 'wordpress-seo' ) );
echo $wpseo_admin_pages->textinput( 'og_frontpage_desc', __( 'Description', 'wordpress-seo' ) );
echo '<p><strong>' . esc_html__( 'Frontpage settings', 'wordpress-seo' ) . '</strong></p>';
$yform->media_input( 'og_frontpage_image', __( 'Image URL', 'wordpress-seo' ) );
$yform->textinput( 'og_frontpage_title', __( 'Title', 'wordpress-seo' ) );
$yform->textinput( 'og_frontpage_desc', __( 'Description', 'wordpress-seo' ) );
// Offer copying of meta description
$meta_options = get_option( 'wpseo_titles' );
echo '<input type="hidden" id="meta_description" value="' . $meta_options['metadesc-home-wpseo'] . '" />';
echo '<p class="label desc" style="border:0;"><a href="javascript:;" onclick="copy_home_meta();" class="button">' . __( 'Copy home meta description', 'wordpress-seo' ) . '</a></p>';
echo '<input type="hidden" id="meta_description" value="', esc_attr( $meta_options['metadesc-home-wpseo'] ), '" />';
echo '<p class="label desc" style="border:0;"><a href="javascript:;" onclick="copy_home_meta();" class="button">', esc_html__( 'Copy home meta description', 'wordpress-seo' ), '</a></p>';
echo '<p class="desc label">' . esc_html__( 'These are the title, description and image used in the Open Graph meta tags on the front page of your site.', 'wordpress-seo' ) . '</p>';
}
echo '<h4>' . esc_html__( 'Default settings', 'wordpress-seo' ) . '</h4>';
echo $wpseo_admin_pages->media_input( 'og_default_image', __( 'Image URL', 'wordpress-seo' ) );
echo '<p class="desc label">' . esc_html__( 'This image is used if the post/page being shared does not contain any images.', 'wordpress-seo' ) . '</p>';
do_action( 'wpseo_admin_opengraph_section' );
?>
</div>
} ?>
<div id="twitterbox" class="wpseotab">
<?php
echo '<p><strong>';
printf( esc_html__( 'Note that for the Twitter Cards to work, you have to check the box below and then validate your Twitter Cards through the %1$sTwitter Card Validator%2$s.', 'wordpress-seo' ), '<a target="_blank" href="https://dev.twitter.com/docs/cards/validation/validator">', '</a>' );
echo '</p></strong>';
echo '<p>';
echo $wpseo_admin_pages->checkbox( 'twitter', __( 'Add Twitter card meta data', 'wordpress-seo' ) );
echo '</p>';
echo'<p class="desc">' . __( 'Add Twitter card meta data to your site\'s <code>&lt;head&gt;</code> section.', 'wordpress-seo' ) . '</p>';
echo $wpseo_admin_pages->textinput( 'twitter_site', __( 'Site Twitter Username', 'wordpress-seo' ) );
echo $wpseo_admin_pages->select( 'twitter_card_type', __( 'The default card type to use', 'wordpress-seo' ), WPSEO_Option_Social::$twitter_card_types );
<p><strong><?php esc_html_e( 'Default settings', 'wordpress-seo' ); ?></strong></p>
<?php $yform->media_input( 'og_default_image', __( 'Image URL', 'wordpress-seo' ) ); ?>
<p class="desc label">
<?php esc_html_e( 'This image is used if the post/page being shared does not contain any images.', 'wordpress-seo' ); ?>
</p>
<?php do_action( 'wpseo_admin_opengraph_section' ); ?>
</div>
<div id="twitterbox" class="wpseotab">
<p>
<?php $yform->checkbox( 'twitter', __( 'Add Twitter card meta data', 'wordpress-seo' ) ); ?>
</p>
<p class="desc">
<?php _e( 'Add Twitter card meta data to your site\'s <code>&lt;head&gt;</code> section.', 'wordpress-seo' ); ?>
</p>
<?php
$yform->select( 'twitter_card_type', __( 'The default card type to use', 'wordpress-seo' ), WPSEO_Option_Social::$twitter_card_types );
do_action( 'wpseo_admin_twitter_section' );
?>
</div>
?>
</div>
<div id="google" class="wpseotab">
<?php
echo '<p>';
echo $wpseo_admin_pages->checkbox( 'googleplus', __( 'Add Google+ specific post meta data', 'wordpress-seo' ) );
echo '</p>';
<div id="pinterest" class="wpseotab">
<p>
<?php _e( 'Pinterest uses Open Graph metadata just like Facebook, so be sure to keep the Open Graph checkbox on the Facebook tab checked if you want to optimize your site for Pinterest.', 'wordpress-seo' ); ?>
</p>
echo $wpseo_admin_pages->textinput( 'plus-publisher', __( 'Google Publisher Page', 'wordpress-seo' ) );
echo '<p class="desc label">' . esc_html__( 'If you have a Google+ page for your business, add that URL here and link it on your Google+ page\'s about page.', 'wordpress-seo' ) . '</p>';
do_action( 'wpseo_admin_googleplus_section' );
?>
</div>
<?php $yform->textinput( 'pinterestverify', __( 'Pinterest verification', 'wordpress-seo' ) ); ?>
<p class="desc label">
<?php printf( __( 'To %1$sverify your site with Pinterest%2$s, add the meta tag here', 'wordpress-seo' ), '<a target="_blank" href="https://help.pinterest.com/en/articles/verify-your-website#meta_tag">', '</a>' ); ?>
</p>
<?php
do_action( 'wpseo_admin_pinterest_section' );
?>
</div>
<div id="google" class="wpseotab">
<p>
<?php $yform->checkbox( 'googleplus', __( 'Add Google+ specific post meta data', 'wordpress-seo' ) ); ?>
</p>
<?php $yform->textinput( 'plus-publisher', __( 'Google Publisher Page', 'wordpress-seo' ) ); ?>
<p class="desc label"><?php esc_html_e( 'If you have a Google+ page for your business, add that URL here and link it on your Google+ page\'s about page.', 'wordpress-seo' ); ?></p>
<?php do_action( 'wpseo_admin_googleplus_section' ); ?>
</div>
<?php
$wpseo_admin_pages->admin_footer();
$yform->admin_footer();
@@ -0,0 +1,55 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$tool_page = (string) filter_input( INPUT_GET, 'tool' );
$yform = Yoast_Form::get_instance();
$yform->admin_header( false );
if ( '' === $tool_page ) {
$tools = array(
'bulk-editor' => array(
'title' => __( 'Bulk editor', 'wordpress-seo' ),
'desc' => __( 'This tool allows you to quickly change titles and descriptions of your posts and pages without having to go into the editor for each page.', 'wordpress-seo' ),
),
'import-export' => array(
'title' => __( 'Import and Export', 'wordpress-seo' ),
'desc' => __( 'Import settings from other SEO plugins and export your settings for re-use on (another) blog.', 'wordpress-seo' ),
),
);
if ( WPSEO_Utils::allow_system_file_edit() === true && ! is_multisite() ) {
$tools['file-editor'] = array(
'title' => __( 'File editor', 'wordpress-seo' ),
'desc' => __( 'This tool allows you to quickly change important files for your SEO, like your robots.txt and, if you have one, your .htaccess file.', 'wordpress-seo' ),
);
}
echo '<p>', __( 'WordPress SEO by Yoast comes with some very powerful built-in tools:', 'wordpress-seo' ), '</p>';
asort( $tools );
echo '<ul class="ul-disc">';
foreach ( $tools as $slug => $tool ) {
echo '<li>';
echo '<strong><a href="', admin_url( 'admin.php?page=wpseo_tools&tool=' . $slug ), '">', $tool['title'], '</a></strong><br/>';
echo $tool['desc'];
echo '</li>';
}
echo '</ul>';
}
else {
echo '<a href="', admin_url( 'admin.php?page=wpseo_tools' ), '">', __( '&laquo; Back to Tools page', 'wordpress-seo' ), '</a>';
require_once WPSEO_PATH . 'admin/views/tool-' . $tool_page . '.php';
}
$yform->admin_footer( false );
@@ -1,6 +1,6 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
*/
/**
@@ -18,85 +18,108 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$yform = Yoast_Form::get_instance();
$wpseo_admin_pages->admin_header( true, WPSEO_Options::get_group_name( 'wpseo_xml' ), 'wpseo_xml' );
$yform->admin_header( true, 'wpseo_xml' );
$options = get_option( 'wpseo_xml' );
$content = $wpseo_admin_pages->checkbox( 'enablexmlsitemap', __( 'Check this box to enable XML sitemap functionality.', 'wordpress-seo' ), false );
$content .= '<div id="sitemapinfo">';
if ( wpseo_is_nginx() ) {
$content .= '<div style="margin: 5px 0; padding: 3px 10px; background-color: #ffffe0; border: 1px solid #E6DB55; border-radius: 3px;">';
$content .= '<p>' . __( 'As you\'re on NGINX, you\'ll need the following rewrites:', 'wordpress-seo' ) . '</p>';
$content .= '<pre>rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last;
rewrite ^/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;</pre>';
$content .= '</div>';
}
echo '<br/>';
if ( $options['enablexmlsitemap'] === true ) {
$content .= '<p>' . sprintf( esc_html__( 'You can find your XML Sitemap here: %sXML Sitemap%s', 'wordpress-seo' ), '<a target="_blank" class="button-secondary" href="' . esc_url( wpseo_xml_sitemaps_base_url( 'sitemap_index.xml' ) ) . '">', '</a>' ) . '<br/><br/>' . __( 'You do <strong>not</strong> need to generate the XML sitemap, nor will it take up time to generate after publishing a post.', 'wordpress-seo' ) . '</p>';
} else {
$content .= '<p>' . __( 'Save your settings to activate XML Sitemaps.', 'wordpress-seo' ) . '</p>';
}
$yform->checkbox( 'enablexmlsitemap', __( 'Check this box to enable XML sitemap functionality.', 'wordpress-seo' ), false );
// When we write the help tab for this we should definitely reference this plugin :https://wordpress.org/plugins/edit-author-slug/
$content .= '<h2>' . __( 'User sitemap', 'wordpress-seo' ) . '</h2>';
$content .= $wpseo_admin_pages->checkbox( 'disable_author_sitemap', __( 'Disable author/user sitemap', 'wordpress-seo' ), false );
?>
<div id="sitemapinfo">
<br/>
$content .= '<div id="xml_user_block">';
$content .= '<p><strong>' . __( 'Exclude users without posts', 'wordpress-seo' ) . '</strong><br/>';
$content .= $wpseo_admin_pages->checkbox( 'disable_author_noposts', __( 'Disable all users with zero posts', 'wordpress-seo' ), false );
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="general-tab" href="#top#general"><?php _e( 'General', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="user-sitemap-tab"
href="#top#user-sitemap"><?php _e( 'User sitemap', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="post-types-tab"
href="#top#post-types"><?php _e( 'Post Types', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="taxonomies-tab"
href="#top#taxonomies"><?php _e( 'Taxonomies', 'wordpress-seo' ); ?></a>
</h2>
$roles = wpseo_get_roles();
if ( is_array( $roles ) && $roles !== array() ) {
$content .= '<p><strong>' . __( 'Exclude user roles', 'wordpress-seo' ) . '</strong><br/>';
$content .= __( 'Please check the appropriate box below if there\'s a user role that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $roles as $role_key => $role_name ) {
$content .= $wpseo_admin_pages->checkbox( 'user_role-' . $role_key . '-not_in_sitemap', $role_name );
}
}
$content .= '</div>';
<div id="general" class="wpseotab">
<?php
$content .= '<br/>';
$content .= '<h2>' . __( 'General settings', 'wordpress-seo' ) . '</h2>';
$content .= '<p>' . __( 'After content publication, the plugin automatically pings Google and Bing, do you need it to ping other search engines too? If so, check the box:', 'wordpress-seo' ) . '</p>';
$content .= $wpseo_admin_pages->checkbox( 'xml_ping_yahoo', __( 'Ping Yahoo!', 'wordpress-seo' ), false );
$content .= $wpseo_admin_pages->checkbox( 'xml_ping_ask', __( 'Ping Ask.com', 'wordpress-seo' ), false );
if ( $options['enablexmlsitemap'] === true ) {
echo '<p>';
printf( esc_html__( 'You can find your XML Sitemap here: %sXML Sitemap%s', 'wordpress-seo' ), '<a target="_blank" class="button-secondary" href="' . esc_url( wpseo_xml_sitemaps_base_url( 'sitemap_index.xml' ) ) . '">', '</a>' );
echo '<br/>';
echo '<br/>';
_e( 'You do <strong>not</strong> need to generate the XML sitemap, nor will it take up time to generate after publishing a post.', 'wordpress-seo' );
echo '</p>';
}
else {
echo '<p>', __( 'Save your settings to activate XML Sitemaps.', 'wordpress-seo' ), '</p>';
}
?>
<p>
<strong><?php _e( 'Entries per page', 'wordpress-seo' ); ?></strong><br/>
<?php printf( __( 'Please enter the maximum number of entries per sitemap page (defaults to %s, you might want to lower this to prevent memory issues on some installs):', 'wordpress-seo' ), WPSEO_Options::get_default( 'wpseo_xml', 'entries-per-page' ) ); ?>
</p>
$post_types = apply_filters( 'wpseo_sitemaps_supported_post_types', get_post_types( array( 'public' => true ), 'objects' ) );
if ( is_array( $post_types ) && $post_types !== array() ) {
$content .= '<h2>' . __( 'Exclude post types', 'wordpress-seo' ) . '</h2>';
$content .= '<p>' . __( 'Please check the appropriate box below if there\'s a post type that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $post_types as $pt ) {
$content .= $wpseo_admin_pages->checkbox( 'post_types-' . $pt->name . '-not_in_sitemap', $pt->labels->name . ' (<code>' . $pt->name . '</code>)' );
}
}
<?php
$yform->textinput( 'entries-per-page', __( 'Max entries per sitemap', 'wordpress-seo' ) );
?>
</div>
<div id="user-sitemap" class="wpseotab">
<?php
$yform->checkbox( 'disable_author_sitemap', __( 'Disable author/user sitemap', 'wordpress-seo' ), false );
?>
<div id="xml_user_block">
<p><strong><?php _e( 'Exclude users without posts', 'wordpress-seo' ); ?></strong><br/>
<?php $yform->checkbox( 'disable_author_noposts', __( 'Disable all users with zero posts', 'wordpress-seo' ), false );
$taxonomies = apply_filters( 'wpseo_sitemaps_supported_taxonomies', get_taxonomies( array( 'public' => true ), 'objects' ) );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
$content .= '<h2>' . __( 'Exclude taxonomies', 'wordpress-seo' ) . '</h2>';
$content .= '<p>' . __( 'Please check the appropriate box below if there\'s a taxonomy that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $taxonomies as $tax ) {
if ( isset( $tax->labels->name ) && trim( $tax->labels->name ) != '' ) {
$content .= $wpseo_admin_pages->checkbox( 'taxonomies-' . $tax->name . '-not_in_sitemap', $tax->labels->name . ' (<code>' . $tax->name . '</code>)' );
}
}
}
$roles = WPSEO_Utils::get_roles();
if ( is_array( $roles ) && $roles !== array() ) {
echo '<p><strong>' . __( 'Exclude user roles', 'wordpress-seo' ) . '</strong><br/>';
echo __( 'Please check the appropriate box below if there\'s a user role that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $roles as $role_key => $role_name ) {
$yform->checkbox( 'user_role-' . $role_key . '-not_in_sitemap', $role_name );
}
} ?>
</div>
</div>
<div id="post-types" class="wpseotab">
$content .= '<br/>';
$content .= '<h2>' . __( 'Entries per page', 'wordpress-seo' ) . '</h2>';
$content .= '<p>' . sprintf( __( 'Please enter the maximum number of entries per sitemap page (defaults to %s, you might want to lower this to prevent memory issues on some installs):', 'wordpress-seo' ), WPSEO_Options::get_default( 'wpseo_xml', 'entries-per-page' ) ) . '</p>';
$content .= $wpseo_admin_pages->textinput( 'entries-per-page', __( 'Max entries per sitemap page', 'wordpress-seo' ) );
<?php
$post_types = apply_filters( 'wpseo_sitemaps_supported_post_types', get_post_types( array( 'public' => true ), 'objects' ) );
if ( is_array( $post_types ) && $post_types !== array() ) {
echo '<p>' . __( 'Please check the appropriate box below if there\'s a post type that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $post_types as $pt ) {
$yform->checkbox( 'post_types-' . $pt->name . '-not_in_sitemap', $pt->labels->name . ' (<code>' . $pt->name . '</code>)' );
}
}
$content .= '<br class="clear"/>';
$content .= '</div>';
?>
$wpseo_admin_pages->postbox( 'xmlsitemaps', __( 'XML Sitemap', 'wordpress-seo' ), $content );
</div>
<div id="taxonomies" class="wpseotab">
<?php
$taxonomies = apply_filters( 'wpseo_sitemaps_supported_taxonomies', get_taxonomies( array( 'public' => true ), 'objects' ) );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
echo '<p>' . __( 'Please check the appropriate box below if there\'s a taxonomy that you do <strong>NOT</strong> want to include in your sitemap:', 'wordpress-seo' ) . '</p>';
foreach ( $taxonomies as $tax ) {
if ( isset( $tax->labels->name ) && trim( $tax->labels->name ) != '' ) {
$yform->checkbox( 'taxonomies-' . $tax->name . '-not_in_sitemap', $tax->labels->name . ' (<code>' . $tax->name . '</code>)' );
}
}
}
?>
</div>
</div>
<?php
do_action( 'wpseo_xmlsitemaps_config' );
$wpseo_admin_pages->admin_footer();
$yform->admin_footer();
@@ -0,0 +1,255 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* Display a list of contributors
*
* @param array $contributors
*/
function wpseo_display_contributors( $contributors ) {
foreach ( $contributors as $username => $dev ) {
echo '<li class="wp-person" id="wp-person-', $username, '">';
echo '<a href="https://github.com/', $username, '"><img src="https://secure.gravatar.com/avatar/', $dev->gravatar, '?s=60" class="gravatar" alt="', $dev->name, '"></a>';
echo '<a class="web" href="https://github.com/', $username, '">', $dev->name, '</a>';
echo '<span class="title">', $dev->role, '</span></li>';
}
}
?>
<div class="wrap about-wrap">
<h1><?php _e( 'Thank you for updating WordPress SEO by Yoast!', 'wordpress-seo' ); ?></h1>
<div class="about-text">
<?php _e( 'On your way to better search rankings!', 'wordpress-seo' ); ?><br/>
<br/>
<?php _e( 'WordPress SEO by Yoast 2.0 helps you optimize your site by making you ready for Google\'s Knowledge Graph and simplifying the WordPress SEO by Yoast admin.', 'wordpress-seo' ); ?>
</div>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" href="#top#new" id="new-tab">
<?php
/* translators: %s: '2.0' version number */
echo sprintf( __( 'What’s New In %s', 'wordpress-seo' ), '2.0' );
?>
</a>
<a class="nav-tab" href="#top#v21" id="v21-tab">2.1</a>
<a class="nav-tab" href="#top#credits" id="credits-tab"><?php _e( 'Credits', 'wordpress-seo' ); ?></a>
</h2>
<div id="new" class="wpseotab">
<div class="changelog headline-feature">
<h2><?php _e( 'Simplified Admin Menus', 'wordpress-seo' ); ?></h2>
<div class="feature-section">
<div class="col">
<h3><?php _e( 'We’ve merged several menu items to make the most important settings stand out more.', 'wordpress-seo' ); ?></h3>
<p><?php _e( 'Not all settings are created equal. Some require their own admin page and really need your attention. Others are more advanced and don’t need changing by everyone. This release helps you by focusing on what’s important.', 'wordpress-seo' ); ?></p>
<p><?php printf( esc_html__( 'Several settings were moved to the %1$sAdvanced page%2$s, the bulk editor, file editor and import & export tools were all moved to the %3$sTools page%2$s.', 'wordpress-seo' ), '<a href="' . admin_url( 'admin.php?page=wpseo_advanced' ) . '">', '</a>', '<a href="' . admin_url( 'admin.php?page=wpseo_tools' ) . '">' ); ?></p>
</div>
<div class="col">
<img class="aligncenter" src="http://uploads.yoast.nl/seo-menu_1A752658.png">
</div>
</div>
<div class="clear"></div>
</div>
<hr>
<div class="changelog headline-feature dfw">
<h2><?php _e( 'Ready for Google’s Knowledge Graph', 'wordpress-seo' ); ?></h2>
<div class="feature-image">
<div class="dfw-container">
<img src="http://uploads.yoast.nl/knowledge-graph_1A752930.png"/>
</div>
<h3><?php _e( 'Knowledge Graph: We’ve got your back!', 'wordpress-seo' ); ?></h3>
<p>
<?php printf( __( 'Google recently rolled out changes that let you specify you or your companies name, social profiles and logo<sup>*</sup>, to use in their %1$sKnowledge Graph%2$s boxes.', 'wordpress-seo' ), '<a href="http://yoa.st/knowledgegraph">', '</a>' ); ?>
<?php printf( __( 'Decide whether you’re a company or a person and add the required info in the %1$sgeneral settings%2$s, then add your %3$ssocial profiles%2$s. We’ll do the rest.', 'wordpress-seo' ), '<a href="' . admin_url( 'admin.php?page=wpseo_dashboard#top#knowledge-graph' ) . '">', '</a>', '<a href="' . admin_url( 'admin.php?page=wpseo_social' ) . '">' ); ?>
</p>
<p><sup>*</sup>
<small><?php _e( 'Logo only works for companies.', 'wordpress-seo' ); ?></small>
</p>
</div>
</div>
<hr>
<div class="changelog feature-list finer-points">
<h2><?php _e( 'More in this release', 'wordpress-seo' ); ?></h2>
<div class="feature-section col two-col">
<div>
<span class="dashicons dashicons-twitter"></span>
<h4><?php _e( 'Twitter Galleries', 'wordpress-seo' ); ?></h4>
<h2>WordPress SEO 2.0.1</h2>
<p><small>Release date: April 1st, 2015</small></p>
<p>This update fixes a few small bugs:</p>
<ul class="ul-disc">
<li>Fixes an issue where (in rare cases) people upgrading to 2.0 got stuck in a redirect loop on their admin.</li>
<li>Fixes a broken link in the Dutch translation, causing the Pinterest tab on the Social settings page to overflow into the Google+ tab.</li>
<li>Fixes a small typo on the about page.</li>
</ul>
<p>
<?php printf( __( 'If you use galleries in your posts and have Twitter meta data enabled on %1$sSocial → Twitter%2$s, galleries will now be auto-detected and put out as Gallery Cards. All that’s left for your is to %3$sverify the cards with Twitter%2$s.', 'wordpress-seo' ), '<a href="' . admin_url( 'admin.php?page=wpseo_social#top#twitterbox' ) . '">', '</a>', '<a target="_blank" href="http://yoa.st/twittercardsverify">' ); ?>
</p>
</div>
<div class="last-feature">
<span class="dashicons dashicons-performance"></span>
<h4><?php _e( 'Performance Improvements', 'wordpress-seo' ); ?></h4>
<p>
<?php _e( 'This release has made the code of WordPress SEO by Yoast that runs on the frontend of your site approximately 30% faster.', 'wordpress-seo' ); ?>
</p>
</div>
<div>
<span class="dashicons dashicons-admin-generic"></span>
<h4><?php _e( 'Improved Settings Screens', 'wordpress-seo' ); ?> </h4>
<p>
<?php _e( 'All the settings screens have been updated to use exactly the same, tab-based, styling, making them much more comprehensible.', 'wordpress-seo' ); ?>
</p>
</div>
<div class="last-feature">
<span class="dashicons dashicons-translation"></span>
<h4><?php _e( 'More Translations', 'wordpress-seo' ); ?></h4>
<p>
<?php printf( __( 'WordPress SEO by Yoast ships, at time of release, with 26 translations, of which 10 are complete. That\'s a huge improvement from last time, and we\'re improving every week. Join us at %1$stranslate.yoast.com%2$s!', 'wordpress-seo' ), '<a target="_blank" href="https://translate.yoast.com/projects/wordpress-seo">', '</a>' ); ?>
</p>
</div>
</div>
</div>
<hr>
<div class="return-to-dashboard">
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wpseo_dashboard' ) ); ?>"><?php _e( 'Go to The General settings page →', 'wordpress-seo' ); ?></a>
</div>
</div>
<div id="v21" class="wpseotab">
<h2>WordPress SEO 2.1</h2>
<p><small>Release date: April 20th, 2015</small></p>
<p>WordPress SEO 2.1 adds some more features on top of this release. Read the release notes for more info.</p>
<ul class="ul-disc">
<li>See the <a href="https://wordpress.org/plugins/wordpress-seo/changelog/" target="_blank">changelog</a> for a complete list of changes.</li>
<li>Read our <a href="https://yoast.com/wordpress-seo-2-1-release-notes" target="_blank">release blogpost</a> for a more detailed explanation of the important changes in this release.</li>
<li>Read our <a href="https://yoast.com/coordinated-security-release/" target="_blank">security blogpost</a> for the backstory about a security fix that was included in this release, in coordination with a significant part of the WordPress community.</li>
<li>We've added support for Google's new URL representation in mobile search results. You can read more about it in <a href="https://yoast.com/changing-urls-in-search-results/" target="_blank">this blogpost</a>.</li>
</ul>
<h2>WordPress SEO 2.0.1</h2>
<p><small>Release date: April 1st, 2015</small></p>
<p>This update fixes a few small bugs:</p>
<ul class="ul-disc">
<li>Fixes an issue where (in rare cases) people upgrading to 2.0 got stuck in a redirect loop on their admin.</li>
<li>Fixes a broken link in the Dutch translation, causing the Pinterest tab on the Social settings page to overflow into the Google+ tab.</li>
<li>Fixes a small typo on the about page.</li>
</ul>
</div>
<div id="credits" class="wpseotab">
<p class="about-description">
<?php
printf( __( 'While most of the development team is at %1$sYoast%2$s in the Netherlands, WordPress SEO by Yoast is created by a worldwide team.', 'wordpress-seo' ), '<a target="_blank" href="https://yoast.com/">', '</a>' );
echo ' ';
printf( __( 'Want to help us develop? Read our %1$scontribution guidelines%2$s!', 'wordpress-seo' ), '<a target="_blank" href="http://yoa.st/wpseocontributionguidelines">', '</a>' );
?>
</p>
<h4 class="wp-people-group"><?php _e( 'Project Leaders', 'wordpress-seo' ); ?></h4>
<ul class="wp-people-group " id="wp-people-group-project-leaders">
<?php
$leaders = array(
'jdevalk' => (object) array(
'name' => 'Joost de Valk',
'role' => __( 'Project Lead', 'wordpress-seo' ),
'gravatar' => 'f08c3c3253bf14b5616b4db53cea6b78',
),
'jrfnl' => (object) array(
'name' => 'Juliette Reinders Folmer',
'role' => __( 'Lead Developer', 'wordpress-seo' ),
'gravatar' => 'cbbac3e529102364dc3b026af3cc2988',
),
'omarreiss' => (object) array(
'name' => 'Omar Reiss',
'role' => __( 'Lead Developer', 'wordpress-seo' ),
'gravatar' => '86aaa606a1904e7e0cf9857a663c376e',
),
'tacoverdo' => (object) array(
'name' => 'Taco Verdonschot',
'role' => __( 'QA & Translations Manager', 'wordpress-seo' ),
'gravatar' => 'd2d3ecb38cacd521926979b5c678297b',
),
);
wpseo_display_contributors( $leaders );
?>
</ul>
<h4 class="wp-people-group"><?php _e( 'Contributing Developers', 'wordpress-seo' ); ?></h4>
<ul class="wp-people-group " id="wp-people-group-core-developers">
<?php
$contributors = array(
'andizer' => (object) array(
'name' => 'Andy Meerwaldt',
'role' => __( 'Developer', 'wordpress-seo' ),
'gravatar' => 'a9b43e766915b48031eab78f9916ca8e',
),
'petervw' => (object) array(
'name' => 'Peter van Wilderen',
'role' => __( 'Developer', 'wordpress-seo' ),
'gravatar' => 'e4662ebd4b59d3c196e2ba721d8a1efc',
),
'rarst' => (object) array(
'name' => 'Andrey Savchenko',
'role' => __( 'Developer', 'wordpress-seo' ),
'gravatar' => 'ab89ce39f47b327f1c85e4019e865a71',
),
'CarolineGeven' => (object) array(
'name' => 'Caroline Geven',
'role' => __( 'Developer', 'wordpress-seo' ),
'gravatar' => 'f2596a568c3974e35f051266a63d791f',
),
);
wpseo_display_contributors( $contributors );
?>
</ul>
<h4 class="wp-people-group"><?php _e( 'Contributors to this release', 'wordpress-seo' ); ?></h4>
<?php
$patches_from = array(
'Jack Neary' => 'https://github.com/xeeeveee',
'Koen Van den Wijngaert' => 'https://github.com/vdwijngaert',
'Ezra Pool' => 'https://github.com/Zae',
'Andy Sozot' => 'https://github.com/sozot',
);
?>
<p><?php _e( 'We\'re always grateful for patches from non-regular contributors, this release, patches from the following people made it in:', 'wordpress-seo' ); ?></p>
<ul class="ul-square">
<?php
foreach ( $patches_from as $patcher => $link ) {
echo '<li><a href="', esc_url( $link ), '">', $patcher, '</a></li>';
}
?>
</ul>
</div>
</div>
@@ -0,0 +1,85 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$yform = Yoast_Form::get_instance();
$yform->currentoption = 'wpseo_internallinks';
$yform->checkbox( 'breadcrumbs-enable', __( 'Enable Breadcrumbs', 'wordpress-seo' ) );
echo '<br/>';
echo '<div id="breadcrumbsinfo">';
$yform->textinput( 'breadcrumbs-sep', __( 'Separator between breadcrumbs', 'wordpress-seo' ) );
$yform->textinput( 'breadcrumbs-home', __( 'Anchor text for the Homepage', 'wordpress-seo' ) );
$yform->textinput( 'breadcrumbs-prefix', __( 'Prefix for the breadcrumb path', 'wordpress-seo' ) );
$yform->textinput( 'breadcrumbs-archiveprefix', __( 'Prefix for Archive breadcrumbs', 'wordpress-seo' ) );
$yform->textinput( 'breadcrumbs-searchprefix', __( 'Prefix for Search Page breadcrumbs', 'wordpress-seo' ) );
$yform->textinput( 'breadcrumbs-404crumb', __( 'Breadcrumb for 404 Page', 'wordpress-seo' ) );
echo '<br/>';
if ( get_option( 'show_on_front' ) == 'page' && get_option( 'page_for_posts' ) > 0 ) {
$yform->checkbox( 'breadcrumbs-blog-remove', __( 'Remove Blog page from Breadcrumbs', 'wordpress-seo' ) );
}
$yform->checkbox( 'breadcrumbs-boldlast', __( 'Bold the last page in the breadcrumb', 'wordpress-seo' ) );
echo '<br/><br/>';
$post_types = get_post_types( array( 'public' => true ), 'objects' );
if ( is_array( $post_types ) && $post_types !== array() ) {
echo '<strong>' . __( 'Taxonomy to show in breadcrumbs for:', 'wordpress-seo' ) . '</strong><br/>';
foreach ( $post_types as $pt ) {
$taxonomies = get_object_taxonomies( $pt->name, 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
$values = array( 0 => __( 'None', 'wordpress-seo' ) );
foreach ( $taxonomies as $tax ) {
$values[ $tax->name ] = $tax->labels->singular_name;
}
$yform->select( 'post_types-' . $pt->name . '-maintax', $pt->labels->name, $values );
unset( $values, $tax );
}
unset( $taxonomies );
}
unset( $pt );
}
echo '<br/>';
$taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false ), 'objects' );
if ( is_array( $taxonomies ) && $taxonomies !== array() ) {
echo '<strong>' . __( 'Post type archive to show in breadcrumbs for:', 'wordpress-seo' ) . '</strong><br/>';
foreach ( $taxonomies as $tax ) {
$values = array( 0 => __( 'None', 'wordpress-seo' ) );
if ( get_option( 'show_on_front' ) == 'page' && get_option( 'page_for_posts' ) > 0 ) {
$values['post'] = __( 'Blog', 'wordpress-seo' );
}
if ( is_array( $post_types ) && $post_types !== array() ) {
foreach ( $post_types as $pt ) {
if ( $pt->has_archive ) {
$values[ $pt->name ] = $pt->labels->name;
}
}
unset( $pt );
}
$yform->select( 'taxonomy-' . $tax->name . '-ptparent', $tax->labels->singular_name, $values );
unset( $values, $tax );
}
}
unset( $taxonomies, $post_types );
?>
<br class="clear"/>
</div>
<p>
<strong><?php _e( 'How to insert breadcrumbs in your theme', 'wordpress-seo' ); ?></strong><br/>
<?php printf( __( 'Usage of this breadcrumbs feature is explained %1$shere%2$s. For the more code savvy, insert this in your theme:', 'wordpress-seo' ), '<a href="https://yoast.com/wordpress/plugins/breadcrumbs/" target="_blank">', '</a>' ); ?>
</p>
<pre>
&lt;?php if ( function_exists(&#x27;yoast_breadcrumb&#x27;) ) {
yoast_breadcrumb(&#x27;&lt;p id=&quot;breadcrumbs&quot;&gt;&#x27;,&#x27;&lt;/p&gt;&#x27;);
} ?&gt;
</pre>
@@ -0,0 +1,50 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$yform = Yoast_Form::get_instance();
$yform->currentoption = 'wpseo_permalinks';
echo '<p><strong>', __( 'Change URLs', 'wordpress-seo' ), '</strong></p>';
$yform->checkbox( 'stripcategorybase', __( 'Strip the category base (usually <code>/category/</code>) from the category URL.', 'wordpress-seo' ) );
echo '<p class="desc">' . sprintf( __( 'We suggest using %1$sFV Top Level Categories%2$s, if you insist on keeping this but do know that the feature is very error prone and not <em>that</em> important for your SEO.', 'wordpress-seo' ), '<a href="https://wordpress.org/plugins/fv-top-level-cats/">', '</a>' ) . '</p>';
$yform->checkbox( 'redirectattachment', __( 'Redirect attachment URL\'s to parent post URL.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'Attachments to posts are stored in the database as posts, this means they\'re accessible under their own URL\'s if you do not redirect them, enabling this will redirect them to the post they were attached to.', 'wordpress-seo' ) . '</p>';
echo '<p><strong>', __( 'Clean up permalinks', 'wordpress-seo' ), '</strong></p>';
$yform->checkbox( 'cleanslugs', __( 'Remove stop words from slugs.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'This helps you to create cleaner URLs by automatically removing the stopwords from them.', 'wordpress-seo' ) . '</p>';
$yform->checkbox( 'cleanreplytocom', __( 'Remove the <code>?replytocom</code> variables.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'This prevents threaded replies from working when the user has JavaScript disabled, but on a large site can mean a <em>huge</em> improvement in crawl efficiency for search engines when you have a lot of comments.', 'wordpress-seo' ) . '</p>';
$yform->checkbox( 'trailingslash', __( 'Enforce a trailing slash on all category and tag URL\'s', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'If you choose a permalink for your posts with <code>.html</code>, or anything else but a / on the end, this will force WordPress to add a trailing slash to non-post pages nonetheless.', 'wordpress-seo' ) . '</p>';
$yform->checkbox( 'cleanpermalinks', __( 'Redirect ugly URL\'s to clean permalinks. (Not recommended in many cases!)', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'People make mistakes in their links towards you sometimes, or unwanted parameters are added to the end of your URLs, this allows you to redirect them all away. Please note that while this is a feature that is actively maintained, it is known to break several plugins, and should for that reason be the first feature you disable when you encounter issues after installing this plugin.', 'wordpress-seo' ) . '</p>';
echo '<div id="cleanpermalinksdiv">';
$yform->checkbox( 'cleanpermalink-googlesitesearch', __( 'Prevent cleaning out Google Site Search URL\'s.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'Google Site Search URL\'s look weird, and ugly, but if you\'re using Google Site Search, you probably do not want them cleaned out.', 'wordpress-seo' ) . '</p>';
$yform->checkbox( 'cleanpermalink-googlecampaign', __( 'Prevent cleaning out Google Analytics Campaign & Google AdWords Parameters.', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'If you use Google Analytics campaign parameters starting with <code>?utm_</code>, check this box. You shouldn\'t use these btw, you should instead use the hash tagged version instead.', 'wordpress-seo' ) . '</p>';
$yform->textinput( 'cleanpermalink-extravars', __( 'Other variables not to clean', 'wordpress-seo' ) );
echo '<p class="desc">' . __( 'You might have extra variables you want to prevent from cleaning out, add them here, comma separated.', 'wordpress-seo' ) . '</p>';
echo '</div>';
echo '<p><strong>', __( 'Clean up the <code>&lt;head&gt;</code>', 'wordpress-seo' ), '</strong></p>';
$yform->checkbox( 'hide-rsdlink', __( 'Hide RSD Links', 'wordpress-seo' ) );
$yform->checkbox( 'hide-wlwmanifest', __( 'Hide WLW Manifest Links', 'wordpress-seo' ) );
$yform->checkbox( 'hide-shortlink', __( 'Hide Shortlink for posts', 'wordpress-seo' ) );
$yform->checkbox( 'hide-feedlinks', __( 'Hide RSS Links', 'wordpress-seo' ) );
@@ -0,0 +1,43 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$yform = Yoast_Form::get_instance();
$yform->set_option( 'wpseo_rss' );
echo '<p>' . __( "This feature is used to automatically add content to your RSS, more specifically, it's meant to add links back to your blog and your blog posts, so dumb scrapers will automatically add these links too, helping search engines identify you as the original source of the content.", 'wordpress-seo' ) . '</p>';
$textarea_atts = array(
'cols' => '50',
'rows' => '5',
);
$yform->textarea( 'rssbefore', __( 'Content to put before each post in the feed', 'wordpress-seo' ), '', $textarea_atts );
$yform->textarea( 'rssafter', __( 'Content to put after each post in the feed', 'wordpress-seo' ), '', $textarea_atts );
?>
<p><?php _e( 'You can use the following variables within the content, they will be replaced by the value on the right.', 'wordpress-seo' ); ?></p>
<table>
<tr>
<th><strong>%%AUTHORLINK%%</strong></th>
<td><?php _e( 'A link to the archive for the post author, with the authors name as anchor text.', 'wordpress-seo' ); ?></td>
</tr>
<tr>
<th><strong>%%POSTLINK%%</strong></th>
<td><?php _e( 'A link to the post, with the title as anchor text.', 'wordpress-seo' ); ?></td>
</tr>
<tr>
<th><strong>%%BLOGLINK%%</strong></th>
<td><?php _e( "A link to your site, with your site's name as anchor text.", 'wordpress-seo' ); ?></td>
</tr>
<tr>
<th><strong>%%BLOGDESCLINK%%</strong></th>
<td><?php _e( "A link to your site, with your site's name and description as anchor text.", 'wordpress-seo' ); ?></td>
</tr>
</table>
@@ -1,6 +1,7 @@
<?php
/**
* @package Admin
* @package WPSEO\Admin
* @since 1.5.0
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
@@ -9,8 +10,6 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
exit();
}
global $wpseo_admin_pages;
$options = get_option( 'wpseo' );
$wpseo_bulk_titles_table = new WPSEO_Bulk_Title_Editor_List_Table();
@@ -30,11 +29,10 @@ if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
<div class="wrap wpseo_table_page">
<h2 id="wpseo-title"><?php echo esc_html( get_admin_page_title() ); ?></h2>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab" id="title-tab" href="#top#title"><?php _e( 'Title', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="description-tab" href="#top#description"><?php _e( 'Description', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="description-tab"
href="#top#description"><?php _e( 'Description', 'wordpress-seo' ); ?></a>
</h2>
<div class="tabwrapper">
@@ -0,0 +1,134 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
$robots_file = get_home_path() . 'robots.txt';
$ht_access_file = get_home_path() . '.htaccess';
if ( isset( $_POST['create_robots'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot create a robots.txt file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo_create_robots' );
ob_start();
error_reporting( 0 );
do_robots();
$robots_content = ob_get_clean();
$f = fopen( $robots_file, 'x' );
fwrite( $f, $robots_content );
}
if ( isset( $_POST['submitrobots'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot edit the robots.txt file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo-robotstxt' );
if ( file_exists( $robots_file ) ) {
$robotsnew = stripslashes( $_POST['robotsnew'] );
if ( is_writable( $robots_file ) ) {
$f = fopen( $robots_file, 'w+' );
fwrite( $f, $robotsnew );
fclose( $f );
$msg = __( 'Updated Robots.txt', 'wordpress-seo' );
}
}
}
if ( isset( $_POST['submithtaccess'] ) ) {
if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'You cannot edit the .htaccess file.', 'wordpress-seo' ) );
}
check_admin_referer( 'wpseo-htaccess' );
if ( file_exists( $ht_access_file ) ) {
$ht_access_new = stripslashes( $_POST['htaccessnew'] );
if ( is_writeable( $ht_access_file ) ) {
$f = fopen( $ht_access_file, 'w+' );
fwrite( $f, $ht_access_new );
fclose( $f );
}
}
}
if ( isset( $msg ) && ! empty( $msg ) ) {
echo '<div id="message" style="width:94%;" class="updated fade"><p>', esc_html( $msg ), '</p></div>';
}
$action_url = network_admin_url( 'admin.php?page=wpseo_tools&tool=file-editor' ); // auto-falls back on admin_url for non-multisite
echo '<h2>', __( 'Robots.txt', 'wordpress-seo' ), '</h2>';
if ( ! file_exists( $robots_file ) ) {
if ( is_writable( get_home_path() ) ) {
echo '<form action="', esc_url( $action_url ), '" method="post" id="robotstxtcreateform">';
wp_nonce_field( 'wpseo_create_robots', '_wpnonce', true, true );
echo '<p>', __( 'You don\'t have a robots.txt file, create one here:', 'wordpress-seo' ), '</p>';
echo '<input type="submit" class="button" name="create_robots" value="', __( 'Create robots.txt file', 'wordpress-seo' ), '">';
echo '</form>';
}
else {
echo '<p>', __( 'If you had a robots.txt file and it was editable, you could edit it from here.', 'wordpress-seo' ), '</p>';
}
}
else {
$f = fopen( $robots_file, 'r' );
$content = '';
if ( filesize( $robots_file ) > 0 ) {
$content = fread( $f, filesize( $robots_file ) );
}
$robots_txt_content = esc_textarea( $content );
if ( ! is_writable( $robots_file ) ) {
echo '<p><em>', __( 'If your robots.txt were writable, you could edit it from here.', 'wordpress-seo' ), '</em></p>';
echo '<textarea class="large-text code" disabled="disabled" rows="15" name="robotsnew">', $robots_txt_content, '</textarea><br/>';
}
else {
echo '<form action="', esc_url( $action_url ), '" method="post" id="robotstxtform">';
wp_nonce_field( 'wpseo-robotstxt', '_wpnonce', true, true );
echo '<p>', __( 'Edit the content of your robots.txt:', 'wordpress-seo' ), '</p>';
echo '<textarea class="large-text code" rows="15" name="robotsnew">', $robots_txt_content, '</textarea><br/>';
echo '<div class="submit"><input class="button" type="submit" name="submitrobots" value="', __( 'Save changes to Robots.txt', 'wordpress-seo' ), '" /></div>';
echo '</form>';
}
}
echo '<h2>', __( '.htaccess file', 'wordpress-seo' ), '</h2>';
if ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'nginx' ) === false ) && file_exists( $ht_access_file ) ) {
$f = fopen( $ht_access_file, 'r' );
$contentht = '';
if ( filesize( $ht_access_file ) > 0 ) {
$contentht = fread( $f, filesize( $ht_access_file ) );
}
$contentht = esc_textarea( $contentht );
if ( ! is_writable( $ht_access_file ) ) {
echo '<p><em>', __( 'If your .htaccess were writable, you could edit it from here.', 'wordpress-seo' ), '</em></p>';
echo '<textarea class="large-text code" disabled="disabled" rows="15" name="robotsnew">', $contentht, '</textarea><br/>';
}
else {
echo '<form action="', esc_url( $action_url ), '" method="post" id="htaccessform">';
wp_nonce_field( 'wpseo-htaccess', '_wpnonce', true, true );
echo '<p>', __( 'Edit the content of your .htaccess:', 'wordpress-seo' ), '</p>';
echo '<textarea class="large-text code" rows="15" name="htaccessnew">', $contentht, '</textarea><br/>';
echo '<div class="submit"><input class="button" type="submit" name="submithtaccess" value="', __( 'Save changes to .htaccess', 'wordpress-seo' ), '" /></div>';
echo '</form>';
}
}
elseif ( ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'nginx' ) === false ) && ! file_exists( $ht_access_file ) ) {
echo '<p>', __( 'If you had a .htaccess file and it was editable, you could edit it from here.', 'wordpress-seo' ), '</p>';
}
@@ -0,0 +1,185 @@
<?php
/**
* @package WPSEO\Admin
*/
if ( ! defined( 'WPSEO_VERSION' ) ) {
header( 'Status: 403 Forbidden' );
header( 'HTTP/1.1 403 Forbidden' );
exit();
}
/**
* @todo [JRF => testers] Extensively test the export & import of the (new) settings!
* If that all works fine, getting testers to export before and after upgrade will make testing easier.
*
* @todo [Yoast] The import for the RSS Footer plugin checks for data already entered via WP SEO,
* the other import routines should do that too.
*/
$yform = Yoast_Form::get_instance();
$replace = false;
if ( isset( $_POST['import'] ) || isset( $_GET['import'] ) ) {
check_admin_referer( 'wpseo-import' );
if ( isset( $_POST['wpseo']['deleteolddata'] ) && $_POST['wpseo']['deleteolddata'] == 'on' ) {
$replace = true;
}
if ( isset( $_POST['wpseo']['importwoo'] ) ) {
$import = new WPSEO_Import_WooThemes_SEO( $replace );
}
if ( isset( $_POST['wpseo']['importaioseo'] ) || isset( $_GET['importaioseo'] ) ) {
$import = new WPSEO_Import_AIOSEO( $replace );
}
if ( isset( $_POST['wpseo']['importheadspace'] ) ) {
$import = new WPSEO_Import_External( $replace );
$import->import_headspace();
}
if ( isset( $_POST['wpseo']['importrobotsmeta'] ) || isset( $_GET['importrobotsmeta'] ) ) {
$import = new WPSEO_Import_External( $replace );
$import->import_robots_meta();
}
if ( isset( $_POST['wpseo']['importrssfooter'] ) ) {
$import = new WPSEO_Import_External( $replace );
$import->import_rss_footer();
}
if ( isset( $_POST['wpseo']['importbreadcrumbs'] ) ) {
$import = new WPSEO_Import_External( $replace );
$import->import_yoast_breadcrumbs();
}
// Allow custom import actions
do_action( 'wpseo_handle_import' );
}
if ( isset( $_FILES['settings_import_file'] ) ) {
check_admin_referer( 'wpseo-import-file' );
$import = new WPSEO_Import();
}
if ( isset( $import ) ) {
/**
* Allow customization of import&export message
* @api string $msg The message.
*/
$msg = apply_filters( 'wpseo_import_message', $import->msg );
// Check if we've deleted old data and adjust message to match it
if ( $replace ) {
$msg .= ' ' . __( 'The old data of the imported plugin was deleted successfully.', 'wordpress-seo' );
}
if ( $msg != '' ) {
echo '<div id="message" class="message updated" style="width:94%;"><p>', $msg, '</p></div>';
}
}
?>
<br/><br/>
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
<a class="nav-tab nav-tab-active" id="wpseo-import-tab"
href="#top#wpseo-import"><?php _e( 'Import', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="wpseo-export-tab" href="#top#wpseo-export"><?php _e( 'Export', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="import-seo-tab"
href="#top#import-seo"><?php _e( 'Import from other SEO plugins', 'wordpress-seo' ); ?></a>
<a class="nav-tab" id="import-other-tab"
href="#top#import-other"><?php _e( 'Import from other plugins', 'wordpress-seo' ); ?></a>
<?php
/**
* Allow adding a custom import tab header
*/
do_action( 'wpseo_import_tab_header' );
?>
</h2>
<div id="wpseo-import" class="wpseotab">
<p><?php _e( 'Import settings by locating <em>settings.zip</em> and clicking "Import settings"', 'wordpress-seo' ); ?></p>
<form
action="<?php echo esc_attr( admin_url( 'admin.php?page=wpseo_tools&tool=import-export#top#wpseo-import' ) ); ?>"
method="post" enctype="multipart/form-data"
accept-charset="<?php echo esc_attr( get_bloginfo( 'charset' ) ); ?>">
<?php wp_nonce_field( 'wpseo-import-file', '_wpnonce', true, true ); ?>
<input type="file" name="settings_import_file" accept="application/x-zip,application/x-zip-compressed,application/zip" />
<input type="hidden" name="action" value="wp_handle_upload"/><br/>
<br/>
<input type="submit" class="button-primary" value="<?php _e( 'Import settings', 'wordpress-seo' ); ?>"/>
</form>
</div>
<div id="wpseo-export" class="wpseotab">
<p><?php _e( 'Export your WordPress SEO settings here, to import them again later or to import them on another site.', 'wordpress-seo' ); ?></p>
<?php $yform->checkbox( 'include_taxonomy_meta', __( 'Include Taxonomy Metadata', 'wordpress-seo' ) ); ?><br/>
<button class="button-primary" id="export-button">Export your WordPress SEO settings</button>
<script>
var wpseo_export_nonce = '<?php echo wp_create_nonce( 'wpseo-export' ); ?>';
</script>
</div>
<div id="import-seo" class="wpseotab">
<p><?php _e( 'No doubt you\'ve used an SEO plugin before if this site isn\'t new. Let\'s make it easy on you, you can import the data below. If you want, you can import first, check if it was imported correctly, and then import &amp; delete. No duplicate data will be imported.', 'wordpress-seo' ); ?></p>
<p><?php printf( __( 'If you\'ve used another SEO plugin, try the %sSEO Data Transporter%s plugin to move your data into this plugin, it rocks!', 'wordpress-seo' ), '<a href="https://wordpress.org/plugins/seo-data-transporter/">', '</a>' ); ?></p>
<form
action="<?php echo esc_attr( admin_url( 'admin.php?page=wpseo_tools&tool=import-export#top#import-seo' ) ); ?>"
method="post" accept-charset="<?php echo esc_attr( get_bloginfo( 'charset' ) ); ?>">
<?php
wp_nonce_field( 'wpseo-import', '_wpnonce', true, true );
$yform->checkbox( 'importheadspace', __( 'Import from HeadSpace2?', 'wordpress-seo' ) );
$yform->checkbox( 'importaioseo', __( 'Import from All-in-One SEO?', 'wordpress-seo' ) );
$yform->checkbox( 'importwoo', __( 'Import from WooThemes SEO framework?', 'wordpress-seo' ) );
?>
<br/>
<?php
$yform->checkbox( 'deleteolddata', __( 'Delete the old data after import? (recommended)', 'wordpress-seo' ) );
?>
<br/>
<input type="submit" class="button-primary" name="import"
value="<?php _e( 'Import', 'wordpress-seo' ); ?>"/>
</form>
<br/>
<br/>
</div>
<div id="import-other" class="wpseotab">
<p><?php _e( 'If you want to import data from (by now ancient) Yoast plugins, you can do so here:', 'wordpress-seo' ); ?></p>
<form
action="<?php echo esc_attr( admin_url( 'admin.php?page=wpseo_tools&tool=import-export#top#import-other' ) ); ?>"
method="post" accept-charset="<?php echo esc_attr( get_bloginfo( 'charset' ) ); ?>">
<?php
wp_nonce_field( 'wpseo-import', '_wpnonce', true, true );
$yform->checkbox( 'importrobotsmeta', __( 'Import from Robots Meta (by Yoast)?', 'wordpress-seo' ) );
$yform->checkbox( 'importrssfooter', __( 'Import from RSS Footer (by Yoast)?', 'wordpress-seo' ) );
$yform->checkbox( 'importbreadcrumbs', __( 'Import from Yoast Breadcrumbs?', 'wordpress-seo' ) );
/**
* Allow option of importing from other 'other' plugins
* @api string $content The content containing all import and export methods
*/
echo apply_filters( 'wpseo_import_other_plugins', '' );
?>
<br/>
<input type="submit" class="button-primary" name="import" value="<?php _e( 'Import', 'wordpress-seo' ); ?>"/>
</form>
<br/>
</div>
<?php
/**
* Allow adding a custom import tab
*/
do_action( 'wpseo_import_tab_content' );
@@ -0,0 +1,54 @@
<?php
/**
* @package WPSEO\Admin
*/
?>
<h3 id="wordpress-seo"><?php _e( 'WordPress SEO settings', 'wordpress-seo' ); ?></h3>
<table class="form-table">
<tr>
<th>
<label
for="wpseo_author_title"><?php _e( 'Title to use for Author page', 'wordpress-seo' ); ?></label>
</th>
<td><input class="regular-text" type="text" id="wpseo_author_title" name="wpseo_author_title"
value="<?php echo esc_attr( get_the_author_meta( 'wpseo_title', $user->ID ) ); ?>"/>
</td>
</tr>
<tr>
<th>
<label
for="wpseo_author_metadesc"><?php _e( 'Meta description to use for Author page', 'wordpress-seo' ); ?></label>
</th>
<td>
<textarea rows="3" cols="30" id="wpseo_author_metadesc"
name="wpseo_author_metadesc"><?php echo esc_textarea( get_the_author_meta( 'wpseo_metadesc', $user->ID ) ); ?></textarea>
</td>
</tr>
<?php if ( $options['usemetakeywords'] === true ) { ?>
<tr>
<th>
<label
for="wpseo_author_metakey"><?php _e( 'Meta keywords to use for Author page', 'wordpress-seo' ); ?></label>
</th>
<td>
<input class="regular-text" type="text" id="wpseo_author_metakey"
name="wpseo_author_metakey"
value="<?php echo esc_attr( get_the_author_meta( 'wpseo_metakey', $user->ID ) ); ?>"/>
</td>
</tr>
<?php } ?>
<tr>
<th>
<label
for="wpseo_author_exclude"><?php _e( 'Exclude user from Author-sitemap', 'wordpress-seo' ); ?></label>
</th>
<td>
<input class="checkbox double" type="checkbox" id="wpseo_author_exclude"
name="wpseo_author_exclude"
value="on" <?php echo ( get_the_author_meta( 'wpseo_excludeauthorsitemap', $user->ID ) == 'on' ) ? 'checked' : ''; ?> />
</td>
</tr>
</table>
<br/><br/>