Merge pull request #1 from woothemes/master

Update from original
This commit is contained in:
Zach Stepek 2015-12-07 10:23:33 -06:00
commit 58eaee3f01
163 changed files with 4642 additions and 3948 deletions

View File

@ -8,7 +8,7 @@ __Please Note:__
GitHub is for _bug reports and contributions only_ - if you have a support question or a request for a customization this is not the right place to post it. Use [WooThemes Support](http://support.woothemes.com) for customer support, [WordPress.org](http://wordpress.org/support/plugin/woocommerce) for community support, and for customizations we recommend one of the following services:
- [Woo Experts](http://www.woothemes.com/experts/)
- [WooExperts](http://www.woothemes.com/experts/)
- [Codeable](https://codeable.io/)
## Contributing To The Core

View File

@ -26,7 +26,7 @@ charset: [UTF-8]
main: WC
# title of generated documentation
title: WooCommerce
title: WooCommerce 2.5.x Code Reference
# base url used for sitemap (useful for public doc)
baseUrl: http://docs.woothemes.com/wc-apidocs/
@ -50,4 +50,4 @@ deprecated: true
todo: true
# add link to ZIP archive of documentation
download: false
download: false

View File

@ -84,7 +84,6 @@ class WC_HookFinder {
echo '<div id="content">';
echo '<h1>Action and Filter Hook Reference</h1>';
echo '<div class="description"><p>The following is a full list of actions and filters found in WooCommerce core.</p></div>';
foreach ( self::$files_to_scan as $heading => $files ) {
self::$custom_hooks_found = array();
@ -151,9 +150,9 @@ class WC_HookFinder {
ksort( self::$custom_hooks_found );
if ( ! empty( self::$custom_hooks_found ) ) {
echo '<h2>' . $heading . '</h2>';
echo '<div class="panel panel-default"><div class="panel-heading"><h2>' . $heading . '</h2></div>';
echo '<table class="summary"><thead><tr><th>Hook</th><th>Type</th><th>File(s)</th></tr></thead><tbody>';
echo '<table class="summary table table-bordered table-striped"><thead><tr><th>Hook</th><th>Type</th><th>File(s)</th></tr></thead><tbody>';
foreach ( self::$custom_hooks_found as $hook => $details ) {
echo '<tr>
@ -163,16 +162,17 @@ class WC_HookFinder {
</tr>' . "\n";
}
echo '</tbody></table>';
echo '</tbody></table></div>';
}
}
echo '</div><div id="footer">';
$html = file_get_contents( '../wc-apidocs/todo.html' );
$html = file_get_contents( '../wc-apidocs/tree.html' );
$header = current( explode( '<div id="content">', $html ) );
$header = str_replace( '<li class="active">', '<li>', $header );
$header = str_replace( '<li class="hooks">', '<li class="active">', $header );
$header = str_replace( 'Tree | ', 'Hook Reference | ', $header );
$footer = end( explode( '<div id="footer">', $html ) );
file_put_contents( '../wc-apidocs/hook-docs.html', $header . ob_get_clean() . $footer );
@ -180,4 +180,4 @@ class WC_HookFinder {
}
}
WC_HookFinder::process_hooks();
WC_HookFinder::process_hooks();

View File

@ -5,32 +5,56 @@
</tr>
{/define}
<table class="summary" id="classes" n:if="$classes">
<caption>Classes summary</caption>
{include elements, elements => $classes}
</table>
{if $classes}
<div class="panel panel-default">
<div class="panel-heading"><h2>Classes summary</h2></div>
<table class="summary table table-bordered table-striped" id="classes">
{include elements, elements => $classes}
</table>
</div>
{/if}
<table class="summary" id="interfaces" n:if="$interfaces">
<caption>Interfaces summary</caption>
{include elements, elements => $interfaces}
</table>
{if $interfaces}
<div class="panel panel-default">
<div class="panel-heading"><h2>Interfaces summary</h2></div>
<table class="summary table table-bordered table-striped" id="interfaces">
{include elements, elements => $interfaces}
</table>
</div>
{/if}
<table class="summary" id="traits" n:if="$traits">
<caption>Traits summary</caption>
{include elements, elements => $traits}
</table>
{if $traits}
<div class="panel panel-default">
<div class="panel-heading"><h2>Traits summary</h2></div>
<table class="summary table table-bordered table-striped" id="traits">
{include elements, elements => $traits}
</table>
</div>
{/if}
<table class="summary" id="exceptions" n:if="$exceptions">
<caption>Exceptions summary</caption>
{include elements, elements => $exceptions}
</table>
{if $exceptions}
<div class="panel panel-default">
<div class="panel-heading"><h2>Exceptions summary</h2></div>
<table class="summary table table-bordered table-striped" id="exceptions">
{include elements, elements => $exceptions}
</table>
</div>
{/if}
<table class="summary" id="constants" n:if="$constants">
<caption>Constants summary</caption>
{include elements, elements => $constants}
</table>
{if $constants}
<div class="panel panel-default">
<div class="panel-heading"><h2>Constants summary</h2></div>
<table class="summary table table-bordered table-striped" id="constants">
{include elements, elements => $constants}
</table>
</div>
{/if}
<table class="summary" id="functions" n:if="$functions">
<caption>Functions summary</caption>
{include elements, elements => $functions}
</table>
{if $functions}
<div class="panel panel-default">
<div class="panel-heading"><h2>Functions summary</h2></div>
<table class="summary table table-bordered table-striped" id="functions">
{include elements, elements => $functions}
</table>
</div>
{/if}

View File

@ -8,6 +8,7 @@
<title>{include title}{if 'overview' !== $active && $config->title} | {$config->title}{/if}</title>
<link rel="stylesheet" href="{='resources/bootstrap.min.css'|staticFile}">
<link rel="stylesheet" href="{='resources/style.css'|staticFile}">
<link n:if="$config->googleCseId" rel="search" type="application/opensearchdescription+xml" title="{$config->title}" href="{$config->baseUrl}/opensearch.xml">
@ -25,27 +26,90 @@
</head>
<body>
<div id="left">
<div id="menu">
<a n:tag-if="'overview' !== $active" href="index.html" title="Overview"><span>Overview</span></a>
<nav id="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a href="index.html" class="navbar-brand">{if $config->title}{$config->title}{else}Overview{/if}</a>
</div>
<div class="collapse navbar-collapse">
<form{if $config->googleCseId} action="http://www.google.com/cse"{/if} id="search" class="navbar-form navbar-left" role="search">
<input type="hidden" name="cx" value="{$config->googleCseId}">
<input type="hidden" name="ie" value="UTF-8">
<div class="form-group">
<input type="text" name="q" class="search-query form-control" placeholder="Search"{if 'overview' === $active} autofocus{/if}>
</div>
</form>
<ul class="nav navbar-nav">
<li n:class="'package' === $active ? active" n:if="$packages">
<a n:tag-if="'package' !== $active && $package" href="{$package|packageUrl}" title="Summary of {$package}"><span>Package</span></a>
</li>
<li n:class="'namespace' === $active ? active" n:if="$namespaces">
<a n:tag-if="'namespace' !== $active && $namespace" href="{$namespace|namespaceUrl}" title="Summary of {$namespace}"><span>Namespace</span></a>
</li>
<li n:class="'class' === $active ? active" n:if="!$function && !$constant">
<a n:tag-if="'class' !== $active && $class" href="{$class|classUrl}" title="Summary of {$class->name}"><span>Class</span></a>
</li>
<li n:class="'function' === $active ? active" n:if="$function">
<a n:tag-if="'function' !== $active" href="{$function|functionUrl}" title="Summary of {$function->name}"><span>Function</span></a>
</li>
<li n:class="'constant' === $active ? active" n:if="$constant">
<a n:tag-if="'constant' !== $active" href="{$constant|constantUrl}" title="Summary of {$constant->name}"><span>Constant</span></a>
</li>
<li class="divider-vertical" n:if="$config->tree || $config->deprecated || $config->todo"></li>
<li n:class="'tree' === $active ? active" n:if="$config->tree">
<a n:tag-if="'tree' !== $active" href="tree.html" title="Tree view of classes, interfaces, traits and exceptions"><span>Tree</span></a>
</li>
{foreach $annotationGroups as $annotation}
<li n:class="$active === 'annotation-group-' . $annotation ? active">
<a n:tag-if="$active !== 'annotation-group-' . $annotation" href="annotation-group-{$annotation}.html" title="List of elements with {$annotation} annotation">
<span>{$annotation|firstUpper}</span>
</a>
</li>
{/foreach}
<li class="divider-vertical"></li>
<li class="hooks">
<a href="hook-docs.html" title="Hooks"><span>Hook Reference</span></a>
</li>
<li class="api">
<a href="http://woothemes.github.io/woocommerce-rest-api-docs/"><span>REST API Docs</span></a>
</li>
<li class="divider-vertical" n:if="$config->download"></li>
<li n:if="$config->download">
<a href="{$archive}" title="Download documentation as ZIP archive"><span>Download</span></a>
</li>
</ul>
</div>
</div>
</nav>
<div id="left">
<div id="menu">
{define group}
<ul>
{foreach $groups as $group}
{var $nextLevel = substr_count($iterator->nextValue, '\\') > substr_count($group, '\\')}
<li n:class="$actualGroup === $group || 0 === strpos($actualGroup, $group . '\\') ? active, $config->main && 0 === strpos($group, $config->main) ? main">
<a href="{if $groupBy === 'package'}{$group|packageUrl}{else}{$group|namespaceUrl}{/if}">
{$group|subgroupName}<span n:tag-if="$nextLevel"></span>
</a>
{if $nextLevel}
<ul>
{else}
</li>
{if substr_count($iterator->nextValue, '\\') < substr_count($group, '\\')}
{='</ul></li>'|repeat:substr_count($group, '\\') - substr_count($iterator->nextValue, '\\')|noescape}
{var $nextLevel = substr_count($iterator->nextValue, '\\') > substr_count($group, '\\')}
<li n:class="$actualGroup === $group || 0 === strpos($actualGroup, $group . '\\') ? active, $config->main && 0 === strpos($group, $config->main) ? main">
<a href="{if $groupBy === 'package'}{$group|packageUrl}{else}{$group|namespaceUrl}{/if}">
{$group|subgroupName}<span n:tag-if="$nextLevel"></span>
</a>
{if $nextLevel}
<ul>
{else}
</li>
{if substr_count($iterator->nextValue, '\\') < substr_count($group, '\\')}
{='</ul></li>'|repeat:substr_count($group, '\\') - substr_count($iterator->nextValue, '\\')|noescape}
{/if}
{/if}
{/if}
{/foreach}
</ul>
{/define}
@ -60,8 +124,6 @@
{/if}
</div>
<hr n:if="($namespaces || $packages) && ($classes || $interfaces || $traits || $exceptions || $constants || $functions)">
{define elements}
<ul>
<li n:foreach="$elements as $element" n:class="$activeElement === $element ? active"><a n:class="$element->deprecated ? deprecated, !$element->valid ? invalid" href="{$element|elementUrl}">{if $namespace}{$element->shortName}{else}{$element->name}{/if}</a></li>
@ -105,62 +167,14 @@
<div id="splitter"></div>
<div id="right">
<div id="rightInner">
<form{if $config->googleCseId} action="http://www.google.com/cse"{/if} id="search">
<input type="hidden" name="cx" value="{$config->googleCseId}">
<input type="hidden" name="ie" value="UTF-8">
<input type="text" name="q" class="text" placeholder="Search"{if 'overview' === $active} autofocus{/if}>
</form>
<div id="navigation">
<ul>
<li n:class="'overview' === $active ? active">
<a n:tag-if="'overview' !== $active" href="index.html" title="Overview"><span>Overview</span></a>
</li>
<li n:class="'package' === $active ? active" n:if="$packages">
<a n:tag-if="'package' !== $active && $package" href="{$package|packageUrl}" title="Summary of {$package}"><span>Package</span></a>
</li>
<li n:class="'namespace' === $active ? active" n:if="$namespaces">
<a n:tag-if="'namespace' !== $active && $namespace" href="{$namespace|namespaceUrl}" title="Summary of {$namespace}"><span>Namespace</span></a>
</li>
<li n:class="'class' === $active ? active" n:if="!$function && !$constant">
<a n:tag-if="'class' !== $active && $class" href="{$class|classUrl}" title="Summary of {$class->name}"><span>Class</span></a>
</li>
<li n:class="'function' === $active ? active" n:if="$function">
<a n:tag-if="'function' !== $active" href="{$function|functionUrl}" title="Summary of {$function->name}"><span>Function</span></a>
</li>
<li n:class="'constant' === $active ? active" n:if="$constant">
<a n:tag-if="'constant' !== $active" href="{$constant|constantUrl}" title="Summary of {$constant->name}"><span>Constant</span></a>
</li>
</ul>
<ul>
<li n:class="'tree' === $active ? active" n:if="$config->tree">
<a href="tree.html" title="Tree view of classes, interfaces, traits and exceptions"><span>Tree</span></a>
</li>
<li n:class="'deprecated' === $active ? active" n:if="$config->deprecated">
<a href="deprecated.html" title="List of deprecated elements"><span>Deprecated</span></a>
</li>
<li n:class="'todo' === $active ? active" n:if="$config->todo">
<a href="todo.html" title="Todo list"><span>Todo</span></a>
</li>
<li class="hooks">
<a href="hook-docs.html" title="Hooks"><span>Hook Reference</span></a>
</li>
</ul>
<ul>
<li n:if="$config->download">
<a href="{$archive}" title="Download documentation as ZIP archive"><span>Download</span></a>
</li>
</ul>
</div>
<div id="rightInner">
{include content}
</div>
<div id="footer">
{$config->title} API documentation generated by <a href="http://apigen.org">ApiGen</a>
</div>
</div>
</div>
<script src="{='resources/combined.js'|staticFile}"></script>
<script src="{='elementlist.js'|staticFile}"></script>
</body>

View File

@ -0,0 +1,149 @@
{layout '@layout.latte'}
{var $active = 'annotation-group-' . $annotation}
{block title}{$annotation|firstUpper}{/block}
{block content}
<div id="content">
<h1>{include title}</h1>
{if $hasElements}
{if $annotationClasses}
<div class="panel panel-default">
<div class="panel-heading"><h2>Classes summary</h2></div>
<table class="summary table table-bordered table-striped" id="classes">
{include classes, items => $annotationClasses}
</table>
</div>
{/if}
{if $annotationInterfaces}
<div class="panel panel-default">
<div class="panel-heading"><h2>Interfaces summary</h2></div>
<table class="summary table table-bordered table-striped" id="interfaces">
{include classes, items => $annotationInterfaces}
</table>
</div>
{/if}
{if $annotationTraits}
<div class="panel panel-default">
<div class="panel-heading"><h2>Traits summary</h2></div>
<table class="summary table table-bordered table-striped" id="traits">
{include classes, items => $annotationTraits}
</table>
</div>
{/if}
{if $annotationExceptions}
<div class="panel panel-default">
<div class="panel-heading"><h2>Exceptions summary</h2></div>
<table class="summary table table-bordered table-striped" id="exceptions">
{include classes, items => $annotationExceptions}
</table>
</div>
{/if}
{if $annotationMethods}
<div class="panel panel-default">
<div class="panel-heading"><h2>Methods summary</h2></div>
<table class="summary table table-bordered table-striped" id="methods">
<tr n:foreach="$annotationMethods as $method">
<td class="name"><a href="{$method->declaringClassName|classUrl}">{$method->declaringClassName}</a></td>
<td class="name"><code><a href="{$method|methodUrl}">{$method->name}()</a></code></td>
<td>
{if $method->hasAnnotation($annotation)}
{foreach $method->annotations[$annotation] as $description}
{if $description}
{$description|annotation:$annotation:$method|noescape}<br>
{/if}
{/foreach}
{/if}
</td>
</tr>
</table>
</div>
{/if}
{if $annotationConstants}
<div class="panel panel-default">
<div class="panel-heading"><h2>Constants summary</h2></div>
<table class="summary table table-bordered table-striped" id="constants">
<tr n:foreach="$annotationConstants as $constant">
{if $constant->declaringClassName}
<td class="name"><a href="{$constant->declaringClassName|classUrl}">{$constant->declaringClassName}</a></td>
<td class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->name}</b></a></code></td>
{else}
<td class="name" n:if="$namespaces || $classes || $interfaces || $traits || $exceptions"><a n:if="$constant->namespaceName" href="{$constant->namespaceName|namespaceUrl}">{$constant->namespaceName}</a></td>
<td n:class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->shortName}</b></a></code></td>
{/if}
<td>
{foreach $constant->annotations[$annotation] as $description}
{if $description}
{$description|annotation:$annotation:$constant|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
</div>
{/if}
{if $annotationProperties}
<div class="panel panel-default">
<div class="panel-heading"><h2>Properties summary</h2></div>
<table class="summary table table-bordered table-striped" id="properties">
<tr n:foreach="$annotationProperties as $property">
<td class="name"><a href="{$property->declaringClassName|classUrl}">{$property->declaringClassName}</a></td>
<td class="name"><a href="{$property|propertyUrl}"><var>${$property->name}</var></a></td>
<td>
{foreach $property->annotations[$annotation] as $description}
{if $description}
{$description|annotation:$annotation:$property|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
</div>
{/if}
{if $annotationFunctions}
<div class="panel panel-default">
<div class="panel-heading"><h2>Functions summary</h2></div>
<table class="summary table table-bordered table-striped" id="functions">
<tr n:foreach="$annotationFunctions as $function">
<td class="name" n:if="$namespaces"><a n:if="$function->namespaceName" href="{$function->namespaceName|namespaceUrl}">{$function->namespaceName}</a></td>
<td class="name"><code><a href="{$function|functionUrl}">{$function->shortName}</a></code></td>
<td>
{foreach $function->annotations[$annotation] as $description}
{if $description}
{$description|annotation:$annotation:$function|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
</div>
{/if}
{else}
<p>No elements with <code>@{$annotation}</code> annotation found.</p>
{/if}
</div>
{/block}
{define classes}
<tr n:foreach="$items as $class">
<td class="name"><a href="{$class|classUrl}">{$class->name}</a></td>
<td>
{foreach $class->annotations[$annotation] as $description}
{if $description}
{$description|annotation:$annotation:$class|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
{/define}

View File

@ -13,7 +13,7 @@
{$class|longDescription|noescape}
</div>
<dl class="tree" n:if="$class->parentClass || $class->ownInterfaces || $class->ownTraits">
<dl class="tree well" n:if="$class->parentClass || $class->ownInterfaces || $class->ownTraits">
<dd n:foreach="$tree as $item" style="padding-left:{($iterator->counter - 1) * 30}px">
<img src="resources/inherit.png" alt="Extended by" n:if="$iterator->counter > 1">
{if $item->documented}
@ -36,42 +36,44 @@
</dl>
{define children}
<p class="elementList">
{foreach $children as $child}
<a href="{$child|classUrl}" n:tag-if="$child->documented"><span n:tag-if="$child->deprecated" class="deprecated">{$child->name}</span></a>{sep}, {/sep}
<code><a href="{$child|classUrl}" n:tag-if="$child->documented"><span n:tag-if="$child->deprecated" class="deprecated">{$child->name}</span></a></code>{sep}, {/sep}
{/foreach}
</p>
{/define}
<div n:if="$directSubClasses">
<h4>Direct known subclasses</h4>
<h3>Direct known subclasses</h3>
{include children, children => $directSubClasses}
</div>
<div n:if="$indirectSubClasses">
<h4>Indirect known subclasses</h4>
<h3>Indirect known subclasses</h3>
{include children, children => $indirectSubClasses}
</div>
<div n:if="$directImplementers">
<h4>Direct known implementers</h4>
<h3>Direct known implementers</h3>
{include children, children => $directImplementers}
</div>
<div n:if="$indirectImplementers">
<h4>Indirect known implementers</h4>
<h3>Indirect known implementers</h3>
{include children, children => $indirectImplementers}
</div>
<div n:if="$directUsers">
<h4>Direct Known Users</h4>
<h3>Direct Known Users</h3>
{include children, children => $directUsers}
</div>
<div n:if="$indirectUsers">
<h4>Indirect Known Users</h4>
<h3>Indirect Known Users</h3>
{include children, children => $indirectUsers}
</div>
<div class="info">
<div class="alert alert-info">
{if !$class->interface && !$class->trait && ($class->abstract || $class->final)}<b>{if $class->abstract}Abstract{else}Final{/if}</b><br>{/if}
{if $class->internal}<b>PHP Extension:</b> <a href="{$class->extension|manualUrl}" title="Go to PHP documentation">{$class->extension->name|firstUpper}</a><br>{/if}
{if $class->inNamespace()}<b>Namespace:</b> {$class->namespaceName|namespaceLinks|noescape}<br>{/if}
@ -92,331 +94,359 @@
</div>
{var $ownMethods = $class->ownMethods}
{var $inheritedMethods = $class->inheritedMethods}
{var $usedMethods = $class->usedMethods}
{var $ownMagicMethods = $class->ownMagicMethods}
{var $inheritedMagicMethods = $class->inheritedMagicMethods}
{var $usedMagicMethods = $class->usedMagicMethods}
{define method}
<tr data-order="{$method->name}" id="{if $method->magic}m{/if}_{$method->name}" n:class="$method->deprecated ? deprecated">
{var $annotations = $method->annotations}
{if $ownMethods || $inheritedMethods || $usedMethods || $ownMagicMethods || $usedMagicMethods}
{define method}
<tr data-order="{$method->name}" id="{if $method->magic}m{/if}_{$method->name}">
{var $annotations = $method->annotations}
<td class="attributes"><code>
{if !$class->interface && $method->abstract}abstract{elseif $method->final}final{/if} {if $method->protected}protected{elseif $method->private}private{else}public{/if} {if $method->static}static{/if}
<td class="attributes"><code>
{if !$class->interface && $method->abstract}abstract{elseif $method->final}final{/if} {if $method->protected}protected{elseif $method->private}private{else}public{/if} {if $method->static}static{/if}
{ifset $annotations['return']}{$annotations['return'][0]|typeLinks:$method|noescape}{/ifset}
{if $method->returnsReference()}&amp;{/if}
</code>
</td>
{ifset $annotations['return']}{$annotations['return'][0]|typeLinks:$method|noescape}{/ifset}
{if $method->returnsReference()}&amp;{/if}
</code>
</td>
<td class="name"><div>
<a class="anchor" href="#{if $method->magic}m{/if}_{$method->name}">#</a>
<code n:class="$method->deprecated ? deprecated">{block|strip}
{if $class->internal}
<a href="{$method|manualUrl}" title="Go to PHP documentation">{$method->name}</a>(
{else}
<a n:tag-if="$config->sourceCode" href="{$method|sourceUrl}" title="Go to source code">{$method->name}</a>(
{/if}
{foreach $method->parameters as $parameter}
<span>{$parameter->typeHint|typeLinks:$method|noescape}
<var>{if $parameter->passedByReference}&amp; {/if}${$parameter->name}</var>{if $parameter->defaultValueAvailable} = {$parameter->defaultValueDefinition|highlightPHP:$class|noescape}{elseif $parameter->unlimited},…{/if}</span>{sep}, {/sep}
{/foreach}
){/block}</code>
<td class="name"><div>
<a class="anchor" href="#{if $method->magic}m{/if}_{$method->name}">#</a>
<code>{block|strip}
{if $class->internal}
<a href="{$method|manualUrl}" title="Go to PHP documentation">{$method->name}</a>(
{else}
<a n:tag-if="$config->sourceCode" href="{$method|sourceUrl}" title="Go to source code">{$method->name}</a>(
{if $config->template['options']['elementDetailsCollapsed']}
<div class="description short">
{$method|shortDescription:true|noescape}
</div>
{/if}
{foreach $method->parameters as $parameter}
<span>{$parameter->typeHint|typeLinks:$method|noescape}
<var>{if $parameter->passedByReference}&amp; {/if}${$parameter->name}</var>{if $parameter->defaultValueAvailable} = {$parameter->defaultValueDefinition|highlightPHP:$class|noescape}{elseif $parameter->unlimited},…{/if}</span>{sep}, {/sep}
{/foreach}
){/block}</code>
{if $config->template['options']['elementDetailsCollapsed']}
<div class="description short">
{$method|shortDescription:true|noescape}
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$method|longDescription|noescape}
{if !$class->deprecated && $method->deprecated}
<h4>Deprecated</h4>
{ifset $annotations['deprecated']}
<div class="list">
{foreach $annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$method|noescape}<br>
{/if}
{/foreach}
</div>
{/ifset}
{/if}
{if $method->parameters && isset($annotations['param'])}
<h4>Parameters</h4>
<div class="list"><dl>
{foreach $method->parameters as $parameter}
<dt><var>${$parameter->name}</var>{if $parameter->unlimited},…{/if}</dt>
<dd>{$parameter->description|description:$method|noescape}</dd>
{/foreach}
</dl></div>
{/if}
{if isset($annotations['return']) && 'void' !== $annotations['return'][0]}
<h4>Returns</h4>
<div class="list">
{foreach $annotations['return'] as $description}
{$description|annotation:'return':$method|noescape}{sep}<br>{/}
{/foreach}
</div>
{/if}
{ifset $annotations['throws']}
<h4>Throws</h4>
<div class="list">
{foreach $annotations['throws'] as $description}
{$description|annotation:'throws':$method|noescape}{sep}<br>{/}
{/foreach}
</div>
{/ifset}
{foreach $template->annotationSort($template->annotationFilter($annotations, array('deprecated', 'param', 'return', 'throws'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$method|noescape}<br>
{/if}
{/foreach}
</div>
{/foreach}
{var $overriddenMethod = $method->overriddenMethod}
{if $overriddenMethod}
<h4>Overrides</h4>
<div class="list"><code><a n:tag-if="$template->getClass($overriddenMethod->declaringClassName)" href="{$overriddenMethod|methodUrl}">{$overriddenMethod->declaringClassName}::{$overriddenMethod->name}</a></code></div>
{/if}
{var $implementedMethod = $method->implementedMethod}
{if $implementedMethod}
<h4>Implementation of</h4>
<div class="list"><code><a n:tag-if="$template->getClass($implementedMethod->declaringClassName)" href="{$implementedMethod|methodUrl}">{$implementedMethod->prettyName}</a></code></div>
{/if}
</div>
</div></td>
</tr>
{/define}
<div class="panel panel-default">
<div class="panel-heading"><h2>Methods summary</h2></div>
<table class="summary table table-bordered table-striped methods" id="methods" n:if="$ownMethods">
{foreach $ownMethods as $method}
{include method, method => $method}
{/foreach}
</table>
</div>
{foreach $inheritedMethods as $parentName => $methods}
<div class="panel panel-default">
<div class="panel-heading"><h3>Methods inherited from <a href="{$parentName|classUrl}#methods" n:tag-if="$template->getClass($parentName)">{$parentName}</a></h3></div>
<p class="elementList">
{foreach $methods as $method}
<code><a href="{$method|methodUrl}" n:tag-if="$template->getClass($parentName)"><span n:tag-if="$method->deprecated" class="deprecated">{$method->name}()</span></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
{foreach $usedMethods as $traitName => $methods}
<div class="panel panel-default">
<div class="panel-heading"><h3>Methods used from <a href="{$traitName|classUrl}#methods" n:tag-if="$template->getClass($traitName)">{$traitName}</a></h3></div>
<p class="elementList">
{foreach $methods as $data}
<code><a href="{$data['method']|methodUrl:$data['method']->declaringTrait}" n:tag-if="$template->getClass($traitName)"><span n:tag-if="$data['method']->deprecated" class="deprecated">{$data['method']->name}()</span></a>{if $data['aliases']}(as {foreach $data['aliases'] as $alias}<span n:tag-if="$data['method']->deprecated" class="deprecated">{$alias->name}()</span>{sep}, {/sep}{/foreach}){/if}</code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
{if $ownMagicMethods}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic methods summary</h3></div>
<table class="summary table table-bordered table-striped methods" id="magicMethods" n:if="$ownMagicMethods">
{foreach $ownMagicMethods as $method}
{include method, method => $method}
{/foreach}
</table>
</div>
{/if}
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$method|longDescription|noescape}
{if !$class->deprecated && $method->deprecated}
<h4>Deprecated</h4>
{ifset $annotations['deprecated']}
<div class="list">
{foreach $annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$method|noescape}<br>
{/if}
{/foreach}
</div>
{/ifset}
{/if}
{if $method->parameters && isset($annotations['param'])}
<h4>Parameters</h4>
<div class="list"><dl>
{foreach $method->parameters as $parameter}
<dt><var>${$parameter->name}</var>{if $parameter->unlimited},…{/if}</dt>
<dd>{$parameter->description|description:$method|noescape}</dd>
{/foreach}
</dl></div>
{/if}
{if isset($annotations['return']) && 'void' !== $annotations['return'][0]}
<h4>Returns</h4>
<div class="list">
{foreach $annotations['return'] as $description}
{$description|annotation:'return':$method|noescape}{sep}<br>{/}
{/foreach}
</div>
{/if}
{ifset $annotations['throws']}
<h4>Throws</h4>
<div class="list">
{foreach $annotations['throws'] as $description}
{$description|annotation:'throws':$method|noescape}{sep}<br>{/}
{/foreach}
</div>
{/ifset}
{foreach $template->annotationSort($template->annotationFilter($annotations, array('deprecated', 'param', 'return', 'throws'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$method|noescape}<br>
{/if}
{/foreach}
</div>
{foreach $inheritedMagicMethods as $parentName => $methods}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic methods inherited from <a href="{$parentName|classUrl}#methods" n:tag-if="$template->getClass($parentName)">{$parentName}</a></h3></div>
<p class="elementList">
{foreach $methods as $method}
<code><a href="{$method|methodUrl}" n:tag-if="$template->getClass($parentName)"><span n:tag-if="$method->deprecated" class="deprecated">{$method->name}()</span></a></code>{sep}, {/sep}
{/foreach}
{var $overriddenMethod = $method->overriddenMethod}
{if $overriddenMethod}
<h4>Overrides</h4>
<div class="list"><code><a n:tag-if="$template->getClass($overriddenMethod->declaringClassName)" href="{$overriddenMethod|methodUrl}">{$overriddenMethod->prettyName}</a></code></div>
{/if}
{var $implementedMethod = $method->implementedMethod}
{if $implementedMethod}
<h4>Implementation of</h4>
<div class="list"><code><a n:tag-if="$template->getClass($implementedMethod->declaringClassName)" href="{$implementedMethod|methodUrl}">{$implementedMethod->prettyName}</a></code></div>
{/if}
</p>
</div>
</div></td>
</tr>
{/define}
<table class="summary methods" id="methods" n:if="$ownMethods">
<caption>Methods summary</caption>
{foreach $ownMethods as $method}
{include method, method => $method}
{/foreach}
</table>
<table n:foreach="$class->inheritedMethods as $parentName => $methods" class="summary inherited">
<caption>Methods inherited from <a href="{$parentName|classUrl}#methods" n:tag-if="$template->getClass($parentName)">{$parentName}</a></caption>
<tr>
<td><code>
{foreach $methods as $method}
<a href="{$method|methodUrl}" n:tag-if="$template->getClass($parentName)"><span n:tag-if="$method->deprecated" class="deprecated">{$method->name}()</span></a>{sep}, {/sep}
{/foreach}
</code></td>
</tr>
</table>
<table n:foreach="$class->usedMethods as $traitName => $methods" class="summary used">
<caption>Methods used from <a href="{$traitName|classUrl}#methods" n:tag-if="$template->getClass($traitName)">{$traitName}</a></caption>
<tr>
<td><code>
{foreach $methods as $data}
<a href="{$data['method']|methodUrl:$data['method']->declaringTrait}" n:tag-if="$template->getClass($traitName)"><span n:tag-if="$data['method']->deprecated" class="deprecated">{$data['method']->name}()</span></a>{if $data['aliases']}(as {foreach $data['aliases'] as $alias}<span n:tag-if="$data['method']->deprecated" class="deprecated">{$alias->name}()</span>{sep}, {/sep}{/foreach}){/if}{sep}, {/sep}
{foreach $usedMagicMethods as $traitName => $methods}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic methods used from <a href="{$traitName|classUrl}#methods" n:tag-if="$template->getClass($traitName)">{$traitName}</a></h3></div>
<p class="elementList">
{foreach $methods as $data}
<code><a href="{$data['method']|methodUrl:$data['method']->declaringTrait}" n:tag-if="$template->getClass($traitName)"><span n:tag-if="$data['method']->deprecated" class="deprecated">{$data['method']->name}()</span></a>{if $data['aliases']}(as {foreach $data['aliases'] as $alias}<span n:tag-if="$data['method']->deprecated" class="deprecated">{$alias->name}()</span>{sep}, {/sep}{/foreach}){/if}</code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
<table class="summary methods" id="magicMethods" n:if="$ownMagicMethods">
<caption>Magic methods summary</caption>
{foreach $ownMagicMethods as $method}
{include method, method => $method}
{/foreach}
</table>
<table n:foreach="$class->inheritedMagicMethods as $parentName => $methods" class="summary inherited">
<caption>Magic methods inherited from <a href="{$parentName|classUrl}#methods" n:tag-if="$template->getClass($parentName)">{$parentName}</a></caption>
<tr>
<td><code>
{foreach $methods as $method}
<a href="{$method|methodUrl}" n:tag-if="$template->getClass($parentName)"><span n:tag-if="$method->deprecated" class="deprecated">{$method->name}()</span></a>{sep}, {/sep}
{/foreach}
</code></td>
</tr>
</table>
<table n:foreach="$class->usedMagicMethods as $traitName => $methods" class="summary used">
<caption>Magic methods used from <a href="{$traitName|classUrl}#methods" n:tag-if="$template->getClass($traitName)">{$traitName}</a></caption>
<tr>
<td><code>
{foreach $methods as $data}
<a href="{$data['method']|methodUrl:$data['method']->declaringTrait}" n:tag-if="$template->getClass($traitName)"><span n:tag-if="$data['method']->deprecated" class="deprecated">{$data['method']->originalName}()</span></a>{if $data['aliases']}(as {foreach $data['aliases'] as $alias}<span n:tag-if="$data['method']->deprecated" class="deprecated">{$alias->name}()</span>{sep}, {/sep}{/foreach}){/if}{sep}, {/sep}
{/foreach}
</code></td>
</tr>
</table>
{/if}
{var $ownConstants = $class->ownConstants}
{var $inheritedConstants = $class->inheritedConstants}
<table class="summary constants" id="constants" n:if="$ownConstants">
<caption>Constants summary</caption>
<tr n:foreach="$ownConstants as $constant" data-order="{$constant->name}" id="{$constant->name}">
{var $annotations = $constant->annotations}
{if $ownConstants || $inheritedConstants}
<div class="panel panel-default">
<div class="panel-heading"><h2>Constants summary</h2></div>
<table class="summary table table-bordered table-striped constants" id="constants" n:if="$ownConstants">
<tr n:foreach="$ownConstants as $constant" data-order="{$constant->name}" id="{$constant->name}">
{var $annotations = $constant->annotations}
<td class="attributes"><code>{$constant->typeHint|typeLinks:$constant|noescape}</code></td>
<td class="name">
<code>
{if $class->internal}
<a href="{$constant|manualUrl}" title="Go to PHP documentation"><b>{$constant->name}</b></a>
{else}
<a n:tag-if="$config->sourceCode" href="{$constant|sourceUrl}" title="Go to source code"><b>{$constant->name}</b></a>
{/if}
</code>
<td class="attributes"><code>{$constant->typeHint|typeLinks:$constant|noescape}</code></td>
<td class="name">
<code>
{if $class->internal}
<a href="{$constant|manualUrl}" title="Go to PHP documentation"><b>{$constant->name}</b></a>
{else}
<a n:tag-if="$config->sourceCode" href="{$constant|sourceUrl}" title="Go to source code"><b>{$constant->name}</b></a>
{/if}
</code>
<div n:if="$config->template['options']['elementDetailsCollapsed']" class="description short">
{$constant|shortDescription:true|noescape}
</div>
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$constant|longDescription|noescape}
{foreach $template->annotationSort($template->annotationFilter($annotations, array('var'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$constant|noescape}<br>
{/if}
{/foreach}
<div n:if="$config->template['options']['elementDetailsCollapsed']" class="description short">
{$constant|shortDescription:true|noescape}
</div>
{/foreach}
</div>
</td>
<td class="value">
<div>
<a href="#{$constant->name}" class="anchor">#</a>
<code>{$constant->valueDefinition|highlightValue:$class|noescape}</code>
</div>
</td>
</tr>
</table>
<table n:foreach="$class->inheritedConstants as $parentName => $constants" class="summary inherited">
<caption>Constants inherited from <a href="{$parentName|classUrl}#constants" n:tag-if="$template->getClass($parentName)">{$parentName}</a></caption>
<tr>
<td><code>
{foreach $constants as $constant}
<a href="{$constant|constantUrl}" n:tag-if="$template->getClass($parentName)"><b><span n:tag-if="$constant->deprecated" class"deprecated">{$constant->name}</span></b></a>{sep}, {/sep}
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$constant|longDescription|noescape}
{foreach $template->annotationSort($template->annotationFilter($annotations, array('var'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$constant|noescape}<br>
{/if}
{/foreach}
</div>
{/foreach}
</div>
</td>
<td class="value">
<div>
<a href="#{$constant->name}" class="anchor">#</a>
<code>{$constant->valueDefinition|highlightValue:$class|noescape}</code>
</div>
</td>
</tr>
</table>
</div>
{foreach $inheritedConstants as $parentName => $constants}
<div class="panel panel-default">
<div class="panel-heading"><h3>Constants inherited from <a href="{$parentName|classUrl}#constants" n:tag-if="$template->getClass($parentName)">{$parentName}</a></h3></div>
<p class="elementList">
{foreach $constants as $constant}
<code><a href="{$constant|constantUrl}" n:tag-if="$template->getClass($parentName)"><b><span n:tag-if="$constant->deprecated" class"deprecated">{$constant->name}</span></b></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
{define property}
<tr data-order="{$property->name}" id="{if $property->magic}m{/if}${$property->name}">
<td class="attributes"><code>
{if $property->protected}protected{elseif $property->private}private{else}public{/if} {if $property->static}static{/if} {if $property->readOnly}read-only{elseif $property->writeOnly}write-only{/if}
{$property->typeHint|typeLinks:$property|noescape}
</code></td>
<td class="name">
{if $class->internal}
<a href="{$property|manualUrl}" title="Go to PHP documentation"><var>${$property->name}</var></a>
{else}
<a n:tag-if="$config->sourceCode" href="{$property|sourceUrl}" title="Go to source code"><var>${$property->name}</var></a>
{/if}
<div n:if="$config->template['options']['elementDetailsCollapsed']" class="description short">
{$property|shortDescription:true|noescape}
</div>
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$property|longDescription|noescape}
{foreach $template->annotationSort($template->annotationFilter($property->annotations, array('var'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$property|noescape}<br>
{/if}
{/foreach}
</div>
{/foreach}
</div>
</td>
<td n:if="!$property->magic" class="value">
<div>
<a href="#{if $property->magic}m{/if}${$property->name}" class="anchor">#</a>
<code>{$property->defaultValueDefinition|highlightValue:$class|noescape}</code>
</div>
</td>
</tr>
{/define}
{/if}
{var $ownProperties = $class->ownProperties}
{var $inheritedProperties = $class->inheritedProperties}
{var $usedProperties = $class->usedProperties}
{var $ownMagicProperties = $class->ownMagicProperties}
{var $inheritedMagicProperties = $class->inheritedMagicProperties}
{var $usedMagicProperties = $class->usedMagicProperties}
<table class="summary properties" id="properties" n:if="$ownProperties">
<caption>Properties summary</caption>
{foreach $ownProperties as $property}
{include property, property => $property}
{/foreach}
</table>
{if $ownProperties || $inheritedProperties || $usedProperties || $ownMagicProperties || $inheritedMagicProperties || $usedMagicProperties}
{define property}
<tr data-order="{$property->name}" id="{if $property->magic}m{/if}${$property->name}">
<td class="attributes"><code>
{if $property->protected}protected{elseif $property->private}private{else}public{/if} {if $property->static}static{/if} {if $property->readOnly}read-only{elseif $property->writeOnly}write-only{/if}
{$property->typeHint|typeLinks:$property|noescape}
</code></td>
<table n:foreach="$class->inheritedProperties as $parentName => $properties" class="summary inherited">
<caption>Properties inherited from <a href="{$parentName|classUrl}#properties" n:tag-if="$template->getClass($parentName)">{$parentName}</a></caption>
<tr>
<td><code>
{foreach $properties as $property}
<a href="{$property|propertyUrl}" n:tag-if="$template->getClass($parentName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a>{sep}, {/sep}
<td class="name">
{if $class->internal}
<a href="{$property|manualUrl}" title="Go to PHP documentation"><var>${$property->name}</var></a>
{else}
<a n:tag-if="$config->sourceCode" href="{$property|sourceUrl}" title="Go to source code"><var>${$property->name}</var></a>
{/if}
<div n:if="$config->template['options']['elementDetailsCollapsed']" class="description short">
{$property|shortDescription:true|noescape}
</div>
<div n:class="description, detailed, $config->template['options']['elementDetailsCollapsed'] ? hidden">
{$property|longDescription|noescape}
{foreach $template->annotationSort($template->annotationFilter($property->annotations, array('var'))) as $annotation => $descriptions}
<h4>{$annotation|annotationBeautify}</h4>
<div class="list">
{foreach $descriptions as $description}
{if $description}
{$description|annotation:$annotation:$property|noescape}<br>
{/if}
{/foreach}
</div>
{/foreach}
</div>
</td>
<td n:if="!$property->magic" class="value">
<div>
<a href="#{if $property->magic}m{/if}${$property->name}" class="anchor">#</a>
<code>{$property->defaultValueDefinition|highlightValue:$class|noescape}</code>
</div>
</td>
</tr>
{/define}
<div class="panel panel-default">
<div class="panel-heading"><h2>Properties summary</h2></div>
<table class="summary table table-bordered table-striped properties" id="properties" n:if="$ownProperties">
{foreach $ownProperties as $property}
{include property, property => $property}
{/foreach}
</table>
</div>
{foreach $inheritedProperties as $parentName => $properties}
<div class="panel panel-default">
<div class="panel-heading"><h3>Properties inherited from <a href="{$parentName|classUrl}#properties" n:tag-if="$template->getClass($parentName)">{$parentName}</a></h3></div>
<p class="elementList">
{foreach $properties as $property}
<code><a href="{$property|propertyUrl}" n:tag-if="$template->getClass($parentName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
<table n:foreach="$class->usedProperties as $traitName => $properties" class="summary used">
<caption>Properties used from <a href="{$traitName|classUrl}#properties" n:tag-if="$template->getClass($traitName)">{$traitName}</a></caption>
<tr>
<td><code>
{foreach $properties as $property}
<a href="{$property|propertyUrl:$property->declaringTrait}" n:tag-if="$template->getClass($traitName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a>{sep}, {/sep}
{foreach $usedProperties as $traitName => $properties}
<div class="panel panel-default">
<div class="panel-heading"><h3>Properties used from <a href="{$traitName|classUrl}#properties" n:tag-if="$template->getClass($traitName)">{$traitName}</a></h3></div>
<p class="elementList">
{foreach $properties as $property}
<code><a href="{$property|propertyUrl:$property->declaringTrait}" n:tag-if="$template->getClass($traitName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
<table class="summary properties" id="magicProperties" n:if="$ownMagicProperties">
<caption>Magic properties summary</caption>
{foreach $ownMagicProperties as $property}
{include property, property => $property}
{/foreach}
</table>
{if $ownMagicProperties}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic properties</h3></div>
<table class="summary table table-bordered table-striped properties" id="magicProperties">
{foreach $ownMagicProperties as $property}
{include property, property => $property}
{/foreach}
</table>
</div>
{/if}
<table n:foreach="$class->inheritedMagicProperties as $parentName => $properties" class="summary inherited">
<caption>Magic properties inherited from <a href="{$parentName|classUrl}#properties" n:tag-if="$template->getClass($parentName)">{$parentName}</a></caption>
<tr>
<td><code>
{foreach $properties as $property}
<a href="{$property|propertyUrl}" n:tag-if="$template->getClass($parentName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a>{sep}, {/sep}
{foreach $inheritedMagicProperties as $parentName => $properties}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic properties inherited from <a href="{$parentName|classUrl}#properties" n:tag-if="$template->getClass($parentName)">{$parentName}</a></h3></div>
<p class="elementList">
{foreach $properties as $property}
<code><a href="{$property|propertyUrl}" n:tag-if="$template->getClass($parentName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
<table n:foreach="$class->usedMagicProperties as $traitName => $properties" class="summary used">
<caption>Magic properties used from <a href="{$traitName|classUrl}#properties" n:tag-if="$template->getClass($traitName)">{$traitName}</a></caption>
<tr>
<td><code>
{foreach $properties as $property}
<a href="{$property|propertyUrl:$property->declaringTrait}" n:tag-if="$template->getClass($traitName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a>{sep}, {/sep}
{foreach $usedMagicProperties as $traitName => $properties}
<div class="panel panel-default">
<div class="panel-heading"><h3>Magic properties used from <a href="{$traitName|classUrl}#properties" n:tag-if="$template->getClass($traitName)">{$traitName}</a></h3></div>
<p class="elementList">
{foreach $properties as $property}
<code><a href="{$property|propertyUrl:$property->declaringTrait}" n:tag-if="$template->getClass($traitName)"><var><span n:tag-if="$property->deprecated" class="deprecated">${$property->name}</span></var></a></code>{sep}, {/sep}
{/foreach}
</p>
</div>
{/foreach}
</code></td>
</tr>
</table>
{/if}
{else}
<div class="invalid">
<div class="alert alert-error">
<p>
Documentation of this class could not be generated.
</p>

View File

@ -1 +1 @@
name: "WC ApiGen theme"
name: "Twitter Bootstrap theme"

View File

@ -13,7 +13,7 @@
{$constant|longDescription|noescape}
</div>
<div class="info">
<div class="alert alert-info">
{if $constant->inNamespace()}<b>Namespace:</b> {$constant->namespaceName|namespaceLinks|noescape}<br>{/if}
{if $constant->inPackage()}<b>Package:</b> {$constant->packageName|packageLinks|noescape}<br>{/if}
{foreach $template->annotationSort($template->annotationFilter($constant->annotations, array('var'))) as $annotation => $values}
@ -30,19 +30,21 @@
{var $annotations = $constant->annotations}
<table class="summary" id="vars">
<caption>Value summary</caption>
<tr>
<td class="name"><code>{$constant->typeHint|typeLinks:$constant|noescape}</code></td>
<td class="value">{block|strip}
{var $element = $template->resolveElement($constant->valueDefinition, $constant)}
{if $element}<a href="{$element|constantUrl}">{$constant->valueDefinition}</a>{else}<code>{$constant->valueDefinition|highlightValue:$constant|noescape}</code>{/if}
{/block}</td>
</tr>
</table>
<div class="panel panel-default">
<div class="panel-heading"><h2>Value summary</h2></div>
<table class="summary table table-bordered table-striped" id="vars">
<tr>
<td class="name"><code>{$constant->typeHint|typeLinks:$constant|noescape}</code></td>
<td class="value">{block|strip}
{var $element = $template->resolveElement($constant->valueDefinition, $constant)}
{if $element}<a href="{$element|constantUrl}">{$constant->valueDefinition}</a>{else}<code>{$constant->valueDefinition|highlightValue:$constant|noescape}</code>{/if}
{/block}</td>
</tr>
</table>
</div>
{else}
<div class="invalid">
<div class="alert alert-error">
<p>
Documentation of this constant could not be generated.
</p>

View File

@ -1,110 +0,0 @@
{layout '@layout.latte'}
{var $active = 'deprecated'}
{block title}Deprecated{/block}
{block content}
<div id="content">
<h1>{include title}</h1>
{define classes}
<tr n:foreach="$items as $class">
<td class="name"><a href="{$class|classUrl}">{$class->name}</a></td>
<td>
{foreach $class->annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$class|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
{/define}
<table class="summary" id="classes" n:if="$deprecatedClasses">
<caption>Classes summary</caption>
{include classes, items => $deprecatedClasses}
</table>
<table class="summary" id="interfaces" n:if="$deprecatedInterfaces">
<caption>Interfaces summary</caption>
{include classes, items => $deprecatedInterfaces}
</table>
<table class="summary" id="traits" n:if="$deprecatedTraits">
<caption>Traits summary</caption>
{include classes, items => $deprecatedTraits}
</table>
<table class="summary" id="exceptions" n:if="$deprecatedExceptions">
<caption>Exceptions summary</caption>
{include classes, items => $deprecatedExceptions}
</table>
<table class="summary" id="methods" n:if="$deprecatedMethods">
<caption>Methods summary</caption>
<tr n:foreach="$deprecatedMethods as $method">
<td class="name"><a href="{$method->declaringClassName|classUrl}">{$method->declaringClassName}</a></td>
<td class="name"><code><a href="{$method|methodUrl}">{$method->name}()</a></code></td>
<td>
{if $method->hasAnnotation('deprecated')}
{foreach $method->annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$method|noescape}<br>
{/if}
{/foreach}
{/if}
</td>
</tr>
</table>
<table class="summary" id="constants" n:if="$deprecatedConstants">
<caption>Constants summary</caption>
<tr n:foreach="$deprecatedConstants as $constant">
{if $constant->declaringClassName}
<td class="name"><a href="{$constant->declaringClassName|classUrl}">{$constant->declaringClassName}</a></td>
<td class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->name}</b></a></code></td>
{else}
<td class="name" n:if="$namespaces || $classes || $interfaces || $traits || $exceptions"><a n:if="$constant->namespaceName" href="{$constant->namespaceName|namespaceUrl}">{$constant->namespaceName}</a></td>
<td n:class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->shortName}</b></a></code></td>
{/if}
<td>
{foreach $constant->annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$constant|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
<table class="summary" id="properties" n:if="$deprecatedProperties">
<caption>Properties summary</caption>
<tr n:foreach="$deprecatedProperties as $property">
<td class="name"><a href="{$property->declaringClassName|classUrl}">{$property->declaringClassName}</a></td>
<td class="name"><a href="{$property|propertyUrl}"><var>${$property->name}</var></a></td>
<td>
{foreach $property->annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$property|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
<table class="summary" id="functions" n:if="$deprecatedFunctions">
<caption>Functions summary</caption>
<tr n:foreach="$deprecatedFunctions as $function">
<td class="name" n:if="$namespaces"><a n:if="$function->namespaceName" href="{$function->namespaceName|namespaceUrl}">{$function->namespaceName}</a></td>
<td class="name"><code><a href="{$function|functionUrl}">{$function->shortName}</a></code></td>
<td>
{foreach $function->annotations['deprecated'] as $description}
{if $description}
{$description|annotation:'deprecated':$function|noescape}<br>
{/if}
{/foreach}
</td>
</tr>
</table>
</div>
{/block}

View File

@ -13,7 +13,7 @@
{$function|longDescription|noescape}
</div>
<div class="info">
<div class="alert alert-info">
{if $function->inNamespace()}<b>Namespace:</b> {$function->namespaceName|namespaceLinks|noescape}<br>{/if}
{if $function->inPackage()}<b>Package:</b> {$function->packageName|packageLinks|noescape}<br>{/if}
{foreach $template->annotationSort($template->annotationFilter($function->annotations, array('param', 'return', 'throws'))) as $annotation => $values}
@ -30,43 +30,55 @@
{var $annotations = $function->annotations}
<table class="summary" id="parameters" n:if="$function->numberOfParameters">
<caption>Parameters summary</caption>
<tr n:foreach="$function->parameters as $parameter" id="${$parameter->name}">
<td class="name"><code>{$parameter->typeHint|typeLinks:$function|noescape}</code></td>
<td class="value"><code>{block|strip}
<var>{if $parameter->passedByReference}&amp; {/if}${$parameter->name}</var>{if $parameter->defaultValueAvailable} = {$parameter->defaultValueDefinition|highlightPHP:$function|noescape}{elseif $parameter->unlimited},…{/if}
{/block}</code></td>
<td>{$parameter->description|description:$function}</td>
</tr>
</table>
{if count($function->parameters)}
<div class="panel panel-default">
<div class="panel-heading"><h2>Parameters summary</h2></div>
<table class="summary table table-bordered table-striped" id="parameters">
<tr n:foreach="$function->parameters as $parameter" id="${$parameter->name}">
<td class="name"><code>{$parameter->typeHint|typeLinks:$function|noescape}</code></td>
<td class="value"><code>{block|strip}
<var>{if $parameter->passedByReference}&amp; {/if}${$parameter->name}</var>{if $parameter->defaultValueAvailable} = {$parameter->defaultValueDefinition|highlightPHP:$function|noescape}{elseif $parameter->unlimited},…{/if}
{/block}</code></td>
<td>{$parameter->description|description:$function}</td>
</tr>
</table>
</div>
{/if}
<table class="summary" id="returns" n:if="isset($annotations['return']) && 'void' !== $annotations['return'][0]">
<caption>Return value summary</caption>
<tr>
<td class="name"><code>
{$annotations['return'][0]|typeLinks:$function|noescape}
</code></td>
<td>
{$annotations['return'][0]|description:$function|noescape}
</td>
</tr>
</table>
{if isset($annotations['return']) && 'void' !== $annotations['return'][0]}
<div class="panel panel-default">
<div class="panel-heading"><h2>Return value summary</h2></div>
<table class="summary table table-bordered table-striped" id="returns">
<tr>
<td class="name"><code>
{$annotations['return'][0]|typeLinks:$function|noescape}
</code></td>
<td>
{$annotations['return'][0]|description:$function|noescape}
</td>
</tr>
</table>
</div>
{/if}
<table class="summary" id="throws" n:ifset="$annotations['throws']">
<caption>Thrown exceptions summary</caption>
<tr n:foreach="$annotations['throws'] as $throws">
<td class="name"><code>
{$throws|typeLinks:$function|noescape}
</code></td>
<td>
{$throws|description:$function|noescape}
</td>
</tr>
</table>
{if isset($annotations['throws'])}
<div class="panel panel-default">
<div class="panel-heading"><h2>Thrown exceptions summary</h2></div>
<table class="summary table table-bordered table-striped" id="throws">
<tr n:foreach="$annotations['throws'] as $throws">
<td class="name"><code>
{$throws|typeLinks:$function|noescape}
</code></td>
<td>
{$throws|description:$function|noescape}
</td>
</tr>
</table>
</div>
{/if}
{else}
<div class="invalid">
<div class="alert alert-error">
<p>
Documentation of this function could not be generated.
</p>

View File

@ -1,53 +1,71 @@
/*!
* jQuery Cookie Plugin v1.3.1
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Copyright 2006, 2014 Klaus Hartl
* Released under the MIT license
*/
(function ($, document, undefined) {
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD (Register as an anonymous module)
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function raw(s) {
return s;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decoded(s) {
return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function unRfc2068(value) {
if (value.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
return value;
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function fromJSON(value) {
return config.json ? JSON.parse(value) : value;
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// write
if (value !== undefined) {
options = $.extend({}, config.defaults, options);
// Write
if (value === null) {
options.expires = -1;
}
if (arguments.length > 1 && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
value = config.json ? JSON.stringify(value) : String(value);
return (document.cookie = [
encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
@ -55,22 +73,30 @@
].join(''));
}
// read
var decode = config.raw ? raw : decoded;
var cookies = document.cookie.split('; ');
var result = key ? null : {};
for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = decode(parts.join('='));
// Read
if (key && key === name) {
result = fromJSON(cookie);
var result = key ? undefined : {},
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
cookies = document.cookie ? document.cookie.split('; ') : [],
i = 0,
l = cookies.length;
for (; i < l; i++) {
var parts = cookies[i].split('='),
name = decode(parts.shift()),
cookie = parts.join('=');
if (key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
if (!key) {
result[name] = fromJSON(cookie);
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
@ -80,11 +106,9 @@
config.defaults = {};
$.removeCookie = function (key, options) {
if ($.cookie(key) !== null) {
$.cookie(key, null, options);
return true;
}
return false;
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
})(jQuery, document);
}));

View File

@ -1,5 +1,7 @@
$(window).load(function() {
var $document = $(document);
var $navigation = $('#navigation');
var navigationHeight = $navigation.height();
var $left = $('#left');
var $right = $('#right');
var $rightInner = $('#rightInner');
@ -40,12 +42,13 @@ $(window).load(function() {
// Search autocompletion
var autocompleteFound = false;
var autocompleteFiles = {'c': 'class', 'co': 'constant', 'f': 'function', 'm': 'class', 'mm': 'class', 'p': 'class', 'mp': 'class', 'cc': 'class'};
var $search = $('#search').find('input[name=q]');
var $search = $('#search input[name=q]');
$search
.autocomplete(ApiGen.elements, {
matchContains: true,
scrollHeight: 200,
max: 20,
width: 300,
noRecord: '',
highlight: function(value, term) {
var term = term.toUpperCase().replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1").replace(/[A-Z0-9]/g, function(m, offset) {
@ -68,9 +71,7 @@ $(window).load(function() {
return $(this).width();
}));
// 10px padding
$list
.width(Math.max(maxWidth + 10, $search.innerWidth()))
.css('left', $search.offset().left + $search.outerWidth() - $list.outerWidth());
$list.width(Math.max(maxWidth + 10, $search.innerWidth()));
}
}).result(function(event, data) {
autocompleteFound = true;
@ -92,7 +93,7 @@ $(window).load(function() {
if ('' === query) {
return false;
}
return !autocompleteFound && '' !== $('#search').find('input[name=cx]').val();
return !autocompleteFound && '' !== $('#search input[name=cx]').val();
});
// Save natural order
@ -106,7 +107,7 @@ $(window).load(function() {
// Switch between natural and alphabetical order
var $caption = $('table.summary', $content)
.filter(':has(tr[data-order])')
.find('caption');
.prev('h2');
$caption
.click(function() {
var $this = $(this);
@ -116,7 +117,7 @@ $(window).load(function() {
$.cookie('order', order, {expires: 365});
var attr = 'alphabetical' === order ? 'data-order' : 'data-order-natural';
$this
.closest('table')
.next('table')
.find('tr').sortElements(function(a, b) {
return $(a).attr(attr) > $(b).attr(attr) ? 1 : -1;
});
@ -130,12 +131,17 @@ $(window).load(function() {
// Open details
if (ApiGen.config.options.elementDetailsCollapsed) {
$('tr', $content).filter(':has(.detailed)')
.click(function() {
var $this = $(this);
$('.short', $this).hide();
$('.detailed', $this).show();
});
$(document.body).on('click', 'tr', function(ev) {
var short = this.querySelector('.short')
, detailed = this.querySelector('.detailed')
if (!short || !detailed) return
$(short).toggleClass('hidden')
$(detailed).toggleClass('hidden')
})
}
// Splitter
@ -150,6 +156,13 @@ $(window).load(function() {
$right.css('margin-left', position + splitterWidth);
$splitter.css('left', position);
}
function setNavigationPosition()
{
var height = $(window).height() - navigationHeight;
$left.height(height);
$splitter.height(height);
$right.height(height);
}
function setContentWidth()
{
var width = $rightInner.width();
@ -200,8 +213,11 @@ $(window).load(function() {
if (null !== splitterPosition) {
setSplitterPosition(splitterPosition);
}
setNavigationPosition();
setContentWidth();
$(window).resize(setContentWidth);
$(window)
.resize(setNavigationPosition)
.resize(setContentWidth);
// Select selected lines
var matches = window.location.hash.substr(1).match(/^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$/);
@ -218,7 +234,7 @@ $(window).load(function() {
var $firstLine = $('#' + parseInt(matches[0]));
if ($firstLine.length > 0) {
$document.scrollTop($firstLine.offset().top);
$right.scrollTop($firstLine.position().top);
}
}
@ -227,8 +243,8 @@ $(window).load(function() {
$('.l a').click(function(event) {
event.preventDefault();
var $selectedLine = $(this).parent();
var selectedLine = parseInt($selectedLine.attr('id'));
var selectedLine = $(this).parent().index() + 1;
var $selectedLine = $('pre.code .l').eq(selectedLine - 1);
if (event.shiftKey) {
if (lastLine) {

View File

@ -7,12 +7,16 @@
<div id="content" class="namespace">
<h1>{if $namespace != 'None'}Namespace {$namespace|namespaceLinks:false|noescape}{else}No namespace{/if}</h1>
<table class="summary" id="namespaces" n:if="$subnamespaces">
<caption>Namespaces summary</caption>
<tr n:foreach="$subnamespaces as $namespace">
<td class="name"><a href="{$namespace|namespaceUrl}">{$namespace}</a></td>
</tr>
</table>
{if $subnamespaces}
<div class="panel panel-default">
<div class="panel-heading"><h2>Namespaces summary</h2></div>
<table class="summary table table-bordered table-striped" id="namespaces">
<tr n:foreach="$subnamespaces as $namespace">
<td class="name"><a href="{$namespace|namespaceUrl}">{$namespace}</a></td>
</tr>
</table>
</div>
{/if}
{include '@elementlist.latte'}
</div>

View File

@ -9,29 +9,37 @@
{var $group = false}
<table class="summary" id="namespaces" n:if="$namespaces">
<caption>Namespaces summary</caption>
{foreach $namespaces as $namespace}
{continueIf $config->main && 0 !== strpos($namespace, $config->main)}
<tr>
{var $group = true}
<td class="name"><a href="{$namespace|namespaceUrl}">{$namespace}</a></td>
</tr>
{/foreach}
</table>
{if count($namespaces)}
<div class="panel panel-default">
<div class="panel-heading"><h2>Namespaces summary</h2></div>
<table class="summary table table-bordered table-striped" id="namespaces">
{foreach $namespaces as $namespace}
{continueIf $config->main && 0 !== strpos($namespace, $config->main)}
<tr>
{var $group = true}
<td class="name"><a href="{$namespace|namespaceUrl}">{$namespace}</a></td>
</tr>
{/foreach}
</table>
</div>
{/if}
<table class="summary" id="packages" n:if="count($packages)">
<caption>Packages summary</caption>
{foreach $packages as $package}
{continueIf $config->main && 0 !== strpos($package, $config->main)}
<tr>
{var $group = true}
<td class="name">
<a href="{$package|packageUrl}">{$package}</a>
</td>
</tr>
{/foreach}
</table>
{if count($packages)}
<div class="panel panel-default">
<div class="panel-heading"><h2>Packages summary</h2></div>
<table class="summary table table-bordered table-striped" id="packages">
{foreach $packages as $package}
{continueIf $config->main && 0 !== strpos($package, $config->main)}
<tr>
{var $group = true}
<td class="name">
<a href="{$package|packageUrl}">{$package}</a>
</td>
</tr>
{/foreach}
</table>
</div>
{/if}
{if ! $group}
{include '@elementlist.latte'}

View File

@ -7,12 +7,16 @@
<div id="content" class="package">
<h1>{if $package != 'None'}Package {$package|packageLinks:false|noescape}{else}No package{/if}</h1>
<table class="summary" id="packages" n:if="$subpackages">
<caption>Packages summary</caption>
<tr n:foreach="$subpackages as $package">
<td class="name"><a href="{$package|packageUrl}">{$package}</a></td>
</tr>
</table>
{if $subpackages}
<div class="panel panel-default">
<div class="panel-heading"><h2>Packages summary</h2></div>
<table class="summary table table-bordered table-striped" id="packages">
<tr n:foreach="$subpackages as $package">
<td class="name"><a href="{$package|packageUrl}">{$package}</a></td>
</tr>
</table>
</div>
{/if}
{include '@elementlist.latte'}
</div>

File diff suppressed because one or more lines are too long

View File

@ -1,96 +1,72 @@
body {
font: 13px/1.5 Verdana, 'Geneva CE', lucida, sans-serif;
margin: 0;
padding: 0;
background: #ffffff;
color: #333333;
}
/* Normal styles */
h1, h2, h3, h4, caption {
font-family: 'Trebuchet MS', 'Geneva CE', lucida, sans-serif;
color: #7E506D;
body {
padding: 50px 0 0 0;
}
h1 {
color: #A4698E;
font-size: 230%;
font-weight: normal;
margin: .3em 0;
font-size: 2em;
margin: 0.67em 0;
}
h2 {
color: #A4698E;
font-size: 150%;
font-weight: normal;
margin: -.3em 0 .3em 0;
font-size: 1.5em;
margin: 0.83em 0;
}
h3 {
font-size: 1.6em;
font-weight: normal;
margin-bottom: 2px;
font-size: 1.17em;
margin: 1em 0 0.2em 0;
}
h4 {
font-size: 100%;
font-weight: bold;
padding: 0;
margin: 0;
padding: 0;
}
caption {
border: 1px solid #cccccc;
background: #E6E6E6;
font-weight: bold;
font-size: 1.2em;
padding: 3px 5px;
text-align: left;
.panel-heading h2,
.panel-heading h3 {
margin-top: 0;
margin-bottom: 0;
}
p {
margin: .7em 0 1em;
padding: 0;
.panel > p {
margin: 10px;
}
hr {
margin: 2em 0 1em;
border: none;
border-top: 1px solid #cccccc;
height: 0;
ul, ol {
margin-bottom: 0;
}
a {
color: #A46497;
padding: 3px 1px;
a, a:hover {
text-decoration: none;
}
h1 a {
color: #A4698E;
}
a:hover, a:active, a:focus, a:hover b, a:hover var {
background-color: #A46497;
color: #ffffff !important;
}
code, var, pre {
font-family: monospace;
}
var {
font-weight: bold;
font-style: normal;
color: #ca8a04;
color: #c09853;
}
pre {
margin: 0;
code {
color: #000;
white-space: nowrap;
border: none;
background: transparent;
padding: 0
}
code:empty {
display: none;
}
code a b {
color: #000000;
color: #000;
}
pre code {
white-space: pre;
}
.deprecated {
@ -99,7 +75,7 @@ code a b {
}
.invalid {
color: #e71818;
color: #dd1144;
}
.hidden {
@ -117,6 +93,14 @@ code a b {
/* Menu */
#menu {
padding: 10px;
overflow-x: hidden;
}
#menu h3 {
border-bottom: 1px solid #E7E7E7;
margin-left: -10px;
margin-right: -10px;
padding: 0 10px 5px 10px;
}
#menu ul {
@ -136,27 +120,31 @@ code a b {
#menu a {
display: block;
padding: 0 2px;
padding: 3px;
border-radius: 3px;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
#menu .active > a, #menu > span {
color: #333333;
background: none;
#menu a:hover {
background-color: #a46497;
color: #fff !important;
}
#menu .active > a {
font-weight: bold;
color: #000;
}
#menu .active > a.invalid {
color: #e71818;
}
#menu .active > a:hover, #menu .active > a:active, #menu .active > a:focus {
background-color: #A46497;
color: #dd1144;
}
#menu #groups span {
position: absolute;
top: 4px;
right: 2px;
top: 6px;
right: 3px;
cursor: pointer;
display: block;
width: 12px;
@ -180,6 +168,49 @@ code a b {
display: none;
}
/* Autocomplete */
.ac_results {
border-radius: 4px;
margin-top: 2px;
background-color: #fff;
border: 1px solid #E7E7E7;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
overflow: hidden;
z-index: 99999;
}
.ac_results ul {
display: block;
list-style: none;
padding: 0;
margin: 0;
}
.ac_results li {
margin: 0;
padding: 0 5px;
line-height: 2;
cursor: default;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ac_results li strong {
color: #000;
}
.ac_over {
background-color: #a46497;
color: #fff;
}
.ac_results li.ac_over strong {
color: #fff;
}
/* Right side */
#right {
overflow: auto;
@ -195,113 +226,23 @@ code a b {
min-width: 350px;
}
/* Search */
#search {
float: right;
margin: 3px 8px;
}
#search input.text {
padding: 3px 5px;
width: 250px;
}
/* Autocomplete */
.ac_results {
padding: 0;
border: 1px solid #cccccc;
background-color: #ffffff;
overflow: hidden;
z-index: 99999;
}
.ac_results ul {
width: 100%;
list-style-position: outside;
list-style: none;
padding: 0;
margin: 0;
}
.ac_results li {
margin: 0;
padding: 2px 5px;
cursor: default;
display: block;
font: 12px 'Trebuchet MS', 'Geneva CE', lucida, sans-serif;
line-height: 16px;
overflow: hidden;
white-space: nowrap;
}
.ac_results li strong {
color: #000000;
}
.ac_odd {
background-color: #eeeeee;
}
.ac_over {
background-color: #A46497;
color: #ffffff;
}
.ac_results li.ac_over strong {
color: #ffffff;
}
/* Navigation */
#navigation {
padding: 3px 8px;
background-color: #f6f6f4;
height: 26px;
margin-bottom: 0;
}
#navigation ul {
list-style: none;
margin: 0 8px 4px 0;
padding: 0;
overflow: hidden;
float: left;
.navbar .nav > li > span {
position: relative;
display: block;
color: #777;
line-height: 20px;
padding: 15px;
}
#navigation ul + ul {
border-left: 1px solid #000000;
padding-left: 8px;
}
#navigation ul li {
float: left;
margin: 2px;
padding: 0 3px;
font-family: Verdana, 'Geneva CE', lucida, sans-serif;
color: #808080;
}
#navigation ul li.active {
background-color: #7E506D;
color: #ffffff;
font-weight: bold;
}
#navigation ul li a {
color: #000000;
font-weight: bold;
padding: 0;
}
#navigation ul li.active a {
color: #fff;
}
#navigation ul li span {
float: left;
padding: 0 3px;
}
#navigation ul li a:hover span, #navigation ul li a:active span, #navigation ul li a:focus span {
background-color: #A46497;
.navbar .nav > li.active > span {
background-color: #E7E7E7;
color: #555;
}
/* Content */
@ -310,65 +251,40 @@ code a b {
padding: 5px 15px;
}
.description pre {
padding: .6em;
background: #fcfcf7;
}
#content > .description {
background: #E6E6E6;
padding: 1px 8px;
margin: 1.2em 0;
}
#content > .description pre {
margin: .5em 0;
#content .alert-info {
margin-top: 18px;
}
dl.tree {
margin: 1.2em 0;
padding: 10px;
}
dl.tree dd {
margin: 0;
padding: 0;
line-height: 18px;
}
.info {
margin: 1.2em 0;
.elementList {
line-height: 24px;
}
.summary {
border: 1px solid #cccccc;
border-collapse: collapse;
font-size: 1em;
width: 100%;
margin: 1.2em 0 2.4em;
}
.summary caption {
border-width: 1px 1px 0;
}
.summary caption.switchable {
background: #E6E6E6 url('sort.png') no-repeat center right;
h2.switchable {
background: transparent url('sort.png') no-repeat center right;
cursor: pointer;
}
.summary td {
border: 1px solid #cccccc;
margin: 0;
padding: 3px 10px;
font-size: 1em;
vertical-align: top;
}
.summary td:first-child {
text-align: right;
}
.summary td hr {
margin: 3px -10px;
margin: 8px -8px;
}
#packages.summary td:first-child, #namespaces.summary td:first-child, .inherited.summary td:first-child, .used.summary td:first-child {
@ -379,20 +295,16 @@ dl.tree dd {
background: #f6f6f4;
}
.summary .description pre {
border: .5em solid #E6E6E6;
}
.summary .description p {
margin: 0;
}
.summary .description p + p, .summary .description ul {
margin: 3px 0 0 0;
.class #methods.summary .description p:first-child, .summary .description.detailed h4:first-child {
margin-top: 8px;
}
.summary .description.detailed h4 {
margin-top: 3px;
.summary .description p + p, .summary .description ul, .summary .description pre, .summary .description.detailed h4 {
margin-top: 4px;
}
.summary dl {
@ -403,6 +315,10 @@ dl.tree dd {
margin: 0 0 0 25px;
}
.summary dt, dd {
line-height: 24px;
}
.name, .attributes {
white-space: nowrap;
}
@ -415,10 +331,6 @@ td.name, td.attributes {
width: 1%;
}
td.attributes {
width: 1%;
}
.class .methods .name, .class .properties .name, .class .constants .name {
width: auto;
white-space: normal;
@ -430,6 +342,7 @@ td.attributes {
.class .methods .name > div > code span, .function .value > code {
white-space: nowrap;
display: inline-block;
}
.class .methods td.name > div, .class td.value > div {
@ -437,6 +350,10 @@ td.attributes {
padding-right: 1em;
}
.attributes code, .name code, dd code {
color: #468847;
}
.anchor {
position: absolute;
top: 0;
@ -444,16 +361,12 @@ td.attributes {
line-height: 1;
font-size: 85%;
margin: 0;
color: #A46497 !important;
color: #a46497 !important;
}
.list {
margin: 0 0 5px 25px;
}
div.invalid {
background-color: #fae4e0;
padding: 10px;
line-height: 24px;
}
/* Splitter */
@ -462,7 +375,7 @@ div.invalid {
height: 100%;
width: 5px;
left: 270px;
background: #A4698E url('resize.png') left center no-repeat;
background: #E7E7E7 url('resize.png') left center no-repeat;
cursor: e-resize;
}
@ -472,15 +385,12 @@ div.invalid {
/* Footer */
#footer {
border-top: 1px solid #e9eeef;
border-top: 1px solid #e5e5e5;
clear: both;
color: #a7a7a7;
font-size: 8pt;
text-align: center;
padding: 20px 0 0;
margin: 3em 0 0;
height: 90px;
background: #ffffff;
color: #808080;
text-align: right;
padding: 2em 1em;
margin: 3em 0 40px 0;
}
/* Tree */
@ -517,8 +427,30 @@ div.tree span.padding {
}
/* Source code */
#source {
margin: 1em 0 1em 1em;
border: 1px solid #ccc;
border-radius: 4px;
overflow: auto;
}
#source pre {
padding: 0;
border: none;
overflow: visible;
}
#source .numbers {
float: left;
background-color: transparent;
}
#source .code {
}
.php-keyword1 {
color: #e71818;
color: #468847;
font-weight: bold;
}
@ -527,16 +459,16 @@ div.tree span.padding {
}
.php-var {
color: #7E506D;
color: #c09853;
font-weight: bold;
}
.php-num {
color: #cd0673;
color: #006dcc;
}
.php-quote {
color: #008000;
color: #006dcc;
}
.php-comment {
@ -544,7 +476,7 @@ div.tree span.padding {
}
.xlang {
color: #ff0000;
color: #468847;
font-weight: bold;
}
@ -553,62 +485,43 @@ span.l {
}
span.l.selected {
background: #f6f6f4;
background: #f9f2d2;
}
span.l a {
color: #333333;
}
span.l a:hover, div.l a:active, div.l a:focus {
span.l a:hover, span.l a:active, span.l a:focus {
background: transparent;
color: #333333 !important;
}
span.l .php-var a {
color: #7E506D;
color: #c09853;
}
span.l .php-var a:hover, span.l .php-var a:active, span.l .php-var a:focus {
color: #7E506D !important;
color: #c09853 !important;
}
span.l a.l {
padding-left: 2px;
background: #fbfbfc;
margin-right: 8px;
padding: 2px 2px 2px 8px;
color: #c0c0c0;
}
span.l a.l:hover, span.l a.l:active, span.l a.l:focus {
background: transparent;
background: #fbfbfc;
color: #c0c0c0 !important;
}
#rightInner.medium #navigation {
height: 52px;
}
#rightInner.medium #navigation ul:first-child + ul {
clear: left;
border: none;
padding: 0;
}
/* Small screens */
#rightInner.medium .name, #rightInner.medium .attributes {
white-space: normal;
}
#rightInner.small #search {
float: left;
}
#rightInner.small #navigation {
height: 78px;
}
#rightInner.small #navigation ul:first-child {
clear: both;
}
/* global style */
.left, .summary td.left {
text-align: left;
@ -616,3 +529,41 @@ span.l a.l:hover, span.l a.l:active, span.l a.l:focus {
.right, .summary td.right {
text-align: right;
}
/* Custom styles for Woo */
.navbar-header {
padding: 10px;
}
.navbar-brand {
background: url(woocommerce_logo_white.png) no-repeat left top;
background-size: 149px 30px;
width: 159px;
padding: 30px 0 0 0;
overflow: hidden;
height: 0;
}
#navigation {
background: #3c3c3c;
color: #fff;
}
#navigation a {
color: #fff;
}
.navbar .nav > li > span {
color: #999;
}
.navbar .nav > li > a:hover > span {
color: #a46497;
}
.navbar .nav > li.active > span, .navbar .nav > li.active > a {
background: #a46497;
color: #fff;
}
a {
color: #a46497;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -4,5 +4,9 @@
{block title}File {$fileName}{/block}
{block content}
<pre><code>{$source|replaceRE:'~<span class="line">(\\s*(\\d+):\\s*)</span>([^\\n]*(?:\\n|$))~','<span id="$2" class="l"><a href="#$2">$1</a>$3</span>'|noescape}</code></pre>
<div id="source">
{var $lineRegex = '~<span class="line">(\s*)(\d+):(\s*)</span>([^\\n]*(?:\\n|$))~'}
<pre class="numbers"><code>{$source|replaceRE:$lineRegex,'<span class="l"><a href="#$2">$1$2$3</a></span>'|noescape}</code></pre>
<pre class="code"><code>{$source|replaceRE:$lineRegex,'<span id="$2" class="l">$4</span>'|noescape}</code></pre>
</div>
{/block}

View File

@ -1,111 +0,0 @@
{layout '@layout.latte'}
{var $active = 'todo'}
{block title}Todo{/block}
{block content}
<div id="content">
<h1>{include title}</h1>
{define classes}
{foreach $items as $class}
<tr>
<td class="name right">
<a href="{$class|classUrl}">{$class->name}</a>
</td>
<td>
{foreach $class->annotations['todo'] as $description}
{$description|annotation:'todo':$class|noescape}{sep}<hr>{/sep}
{/foreach}
</td>
</tr>
{/foreach}
{/define}
<table class="summary" id="classes" n:if="$todoClasses">
<caption>Classes summary</caption>
{include classes, items => $todoClasses}
</table>
<table class="summary" id="interfaces" n:if="$todoInterfaces">
<caption>Interfaces summary</caption>
{include classes, items => $todoInterfaces}
</table>
<table class="summary" id="traits" n:if="$todoTraits">
<caption>Traits summary</caption>
{include classes, items => $todoTraits}
</table>
<table class="summary" id="exceptions" n:if="$todoExceptions">
<caption>Exceptions summary</caption>
{include classes, items => $todoExceptions}
</table>
<table class="summary" id="methods" n:if="$todoMethods">
<caption>Methods summary</caption>
{foreach $todoMethods as $method}
<tr>
<td class="name"><a href="{$method->declaringClassName|classUrl}">{$method->declaringClassName}</a></td>
<td class="name"><code><a href="{$method|methodUrl}">{$method->name}()</a></code></td>
<td>
{foreach $method->annotations['todo'] as $description}
{$description|annotation:'todo':$method|noescape}{sep}<hr>{/sep}
{/foreach}
</td>
</tr>
{/foreach}
</table>
<table class="summary" id="constants" n:if="$todoConstants">
<caption>Constants summary</caption>
{foreach $todoConstants as $constant}
<tr>
{if $constant->declaringClassName}
<td class="name"><a href="{$constant->declaringClassName|classUrl}">{$constant->declaringClassName}</a></td>
<td class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->name}</b></a></code></td>
{else}
<td class="name" n:if="$namespaces || $classes || $interfaces || $traits || $exceptions"><a n:if="$constant->namespaceName" href="{$constant->namespaceName|namespaceUrl}">{$constant->namespaceName}</a></td>
<td n:class="name"><code><a href="{$constant|constantUrl}"><b>{$constant->shortName}</b></a></code></td>
{/if}
<td>
{foreach $constant->annotations['todo'] as $description}
{$description|annotation:'todo':$constant|noescape}{sep}<hr>{/sep}
{/foreach}
</td>
</tr>
{/foreach}
</table>
<table class="summary" id="properties" n:if="$todoProperties">
<caption>Properties summary</caption>
{foreach $todoProperties as $property}
<tr>
<td class="name"><a href="{$property->declaringClassName|classUrl}">{$property->declaringClassName}</a></td>
<td class="name"><a href="{$property|propertyUrl}"><var>${$property->name}</var></a></td>
<td>
{foreach $property->annotations['todo'] as $description}
{$description|annotation:'todo':$property|noescape}{sep}<hr>{/sep}
{/foreach}
</td>
</tr>
{/foreach}
</table>
<table class="summary" id="functions" n:if="$todoFunctions">
<caption>Functions summary</caption>
{foreach $todoFunctions as $function}
<tr>
<td class="name" n:if="$namespaces"><a n:if="$function->namespaceName" href="{$function->namespaceName|namespaceUrl}">{$function->namespaceName}</a></td>
<td class="name"><code><a href="{$function|functionUrl}">{$function->shortName}</a></code></td>
<td>
{foreach $function->annotations['todo'] as $description}
{$description|annotation:'todo':$function|noescape}{sep}<hr>{/sep}
{/foreach}
</td>
</tr>
{/foreach}
</table>
</div>
{/block}

View File

@ -45,22 +45,22 @@
<h1>{include title}</h1>
{if $classTree->valid()}
<h3>Classes</h3>
<h2>Classes</h2>
{include tree, tree => $classTree}
{/if}
{if $interfaceTree->valid()}
<h3>Interfaces</h3>
<h2>Interfaces</h2>
{include tree, tree => $interfaceTree}
{/if}
{if $traitTree->valid()}
<h3>Traits</h3>
<h2>Traits</h2>
{include tree, tree => $traitTree}
{/if}
{if $exceptionTree->valid()}
<h3>Exceptions</h3>
<h2>Exceptions</h2>
{include tree, tree => $exceptionTree}
{/if}
</div>

File diff suppressed because one or more lines are too long

View File

@ -157,7 +157,7 @@
}
}
#variable_product_options #message {
#variable_product_options #message, #variable_product_options .notice {
margin: 10px;
}
@ -3142,8 +3142,18 @@ img.help_tip {
}
.handlediv {
width: 27px;
&:before {
content: "\f142" !important;
cursor: pointer;
display: inline-block;
font: 400 20px/1 "Dashicons";
line-height: .5 !important;
padding: 8px 10px;
position: relative;
right: 12px;
top: 0;
}
}

File diff suppressed because one or more lines are too long

View File

@ -317,9 +317,9 @@
}
}
.terms {
text-align: right;
padding: 0 1em 0;
.wc-terms-and-conditions, .terms {
text-align: left;
padding: 0 1em 0 0;
}
#place_order {
@ -443,3 +443,60 @@
}
}
}
/**
* Twenty Sixteen specific styles
*/
.twentysixteen {
.site-main {
margin-right: 7.6923%;
margin-left: 7.6923%;
}
.entry-summary {
margin-right: 0;
margin-left: 0;
}
}
#content {
.twentysixteen {
div.product {
div.images,
div.summary {
width: 46.42857%;
}
}
}
}
@media screen and (min-width: 44.375em) {
.twentysixteen {
.site-main {
margin-right: 23.0769%;
}
}
}
@media screen and (min-width: 56.875em) {
.twentysixteen {
.site-main {
margin-right: 0;
margin-left: 0;
}
}
.no-sidebar {
.twentysixteen {
.site-main {
margin-right: 15%;
margin-left: 15%;
}
.entry-summary {
margin-right: 0;
margin-left: 0;
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -99,16 +99,18 @@
/**
* Products
*/
ul.products {
li.product {
width: 48%;
float: left;
clear: both;
margin: 0 0 2.992em;
&[class*="columns-"] {
ul.products {
li.product {
width: 48%;
float: left;
clear: both;
margin: 0 0 2.992em;
&:nth-child(2n) {
float: right;
clear: none !important;
&:nth-child(2n) {
float: right;
clear: none !important;
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1909,7 +1909,7 @@ p.demo_store {
}
/* added to get around variation image flicker issue */
.product.has-default-attributes {
.product.has-default-attributes.has-children {
> .images {
opacity: 0;
}
@ -1960,3 +1960,23 @@ p.demo_store {
}
}
}
/**
* Twenty Sixteen specific styles
*/
body:not(.search-results) {
.twentysixteen {
.entry-summary {
color: inherit;
font-size: inherit;
line-height: inherit;
}
}
}
.twentysixteen {
.price ins {
background: inherit;
color: inherit;
}
}

View File

@ -768,11 +768,12 @@ jQuery( function( $ ) {
$.ajax({
url: woocommerce_admin_meta_boxes_variations.ajax_url,
data: {
action: 'woocommerce_bulk_edit_variations',
security: woocommerce_admin_meta_boxes_variations.bulk_edit_variations_nonce,
product_id: woocommerce_admin_meta_boxes_variations.post_id,
bulk_action: do_variation_action,
data: data
action: 'woocommerce_bulk_edit_variations',
security: woocommerce_admin_meta_boxes_variations.bulk_edit_variations_nonce,
product_id: woocommerce_admin_meta_boxes_variations.post_id,
product_type: $( '#product-type' ).val(),
bulk_action: do_variation_action,
data: data
},
type: 'POST',
success: function() {

File diff suppressed because one or more lines are too long

View File

@ -221,18 +221,4 @@ jQuery( function ( $ ) {
// Attribute term table
$( 'table.attributes-table tbody tr:nth-child(odd)' ).addClass( 'alternate' );
// Add js validation for product quick edit panel.
$( '#woocommerce-fields .regular_price[type=text], #woocommerce-fields .sale_price[type=text]' ).keyup( function() {
var value = $( this ).val();
var regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.mon_decimal_point + ']+', 'gi' );
var newvalue = value.replace( regex, '' );
if ( value !== newvalue ) {
$( this ).val( newvalue );
$( document.body ).triggerHandler( 'wc_add_error_tip', [ $( this ), 'i18n_mon_decimal_error' ] );
} else {
$( document.body ).triggerHandler( 'wc_remove_error_tip', [ $( this ), 'i18n_mon_decimal_error' ] );
}
});
});

File diff suppressed because one or more lines are too long

View File

@ -17,6 +17,9 @@
unavailable_template = wp.template( 'unavailable-variation-template' ),
$single_variation_wrap = $form.find( '.single_variation_wrap' );
// Always visible since 2.5.0
$single_variation_wrap.show();
// Unbind any existing events
$form.unbind( 'check_variations update_variation_values found_variation' );
$form.find( '.reset_variations' ).unbind( 'click' );
@ -183,9 +186,7 @@
$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change();
} else {
$single_variation.html( template( {
price: variation.price_html,
availability: variation.availability_html,
description: variation.variation_description
variation: variation
} ) );
$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).change();
}
@ -451,12 +452,16 @@
$product_img.wc_set_variation_attr( 'src', variation.image_src );
$product_img.wc_set_variation_attr( 'title', variation.image_title );
$product_img.wc_set_variation_attr( 'alt', variation.image_title );
$product_img.wc_set_variation_attr( 'srcset', variation.image_srcset );
$product_img.wc_set_variation_attr( 'sizes', variation.image_sizes );
$product_link.wc_set_variation_attr( 'href', variation.image_link );
$product_link.wc_set_variation_attr( 'title', variation.image_caption );
} else {
$product_img.wc_reset_variation_attr( 'src' );
$product_img.wc_reset_variation_attr( 'title' );
$product_img.wc_reset_variation_attr( 'alt' );
$product_img.wc_reset_variation_attr( 'srcset' );
$product_img.wc_reset_variation_attr( 'sizes' );
$product_link.wc_reset_variation_attr( 'href' );
$product_link.wc_reset_variation_attr( 'title' );
}

File diff suppressed because one or more lines are too long

View File

@ -21,6 +21,10 @@ jQuery( function( $ ) {
// Payment methods
this.$checkout_form.on( 'click', 'input[name="payment_method"]', this.payment_method_selected );
if ( $( document.body ).hasClass( 'woocommerce-order-pay' ) ) {
this.$order_review.on( 'click', 'input[name="payment_method"]', this.payment_method_selected );
}
// Form submission
this.$checkout_form.on( 'submit', this.submit );
@ -68,7 +72,7 @@ jQuery( function( $ ) {
$payment_methods.filter( ':checked' ).eq(0).trigger( 'click' );
},
get_payment_method: function() {
return $( '#order_review' ).find( 'input[name="payment_method"]:checked' ).val();
return wc_checkout_form.$order_review.find( 'input[name="payment_method"]:checked' ).val();
},
payment_method_selected: function() {
if ( $( '.payment_methods input.input-radio' ).length > 1 ) {
@ -186,12 +190,12 @@ jQuery( function( $ ) {
$parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field' ).addClass( 'woocommerce-validated' );
}
},
update_checkout: function() {
update_checkout: function( event, args ) {
// Small timeout to prevent multiple requests when several fields update at the same time
wc_checkout_form.reset_update_checkout_timer();
wc_checkout_form.updateTimer = setTimeout( wc_checkout_form.update_checkout_action, '5' );
wc_checkout_form.updateTimer = setTimeout( wc_checkout_form.update_checkout_action, '5', args );
},
update_checkout_action: function() {
update_checkout_action: function( args ) {
if ( wc_checkout_form.xhr ) {
wc_checkout_form.xhr.abort();
}
@ -200,54 +204,35 @@ jQuery( function( $ ) {
return;
}
var shipping_methods = [];
args = typeof args !== 'undefined' ? args : {
update_shipping_method: true
};
$( 'select.shipping_method, input[name^="shipping_method"][type="radio"]:checked, input[name^="shipping_method"][type="hidden"]' ).each( function() {
shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();
} );
var payment_method = wc_checkout_form.get_payment_method(),
country = $( '#billing_country' ).val(),
state = $( '#billing_state' ).val(),
postcode = $( 'input#billing_postcode' ).val(),
city = $( '#billing_city' ).val(),
address = $( 'input#billing_address_1' ).val(),
address_2 = $( 'input#billing_address_2' ).val(),
s_country,
s_state,
s_postcode,
s_city,
s_address,
s_address_2;
var country = $( '#billing_country' ).val(),
state = $( '#billing_state' ).val(),
postcode = $( 'input#billing_postcode' ).val(),
city = $( '#billing_city' ).val(),
address = $( 'input#billing_address_1' ).val(),
address_2 = $( 'input#billing_address_2' ).val(),
s_country = country,
s_state = state,
s_postcode = postcode,
s_city = city,
s_address = address,
s_address_2 = address_2;
if ( $( '#ship-to-different-address' ).find( 'input' ).is( ':checked' ) ) {
s_country = $( '#shipping_country' ).val();
s_state = $( '#shipping_state' ).val();
s_postcode = $( 'input#shipping_postcode' ).val();
s_city = $( '#shipping_city' ).val();
s_address = $( 'input#shipping_address_1' ).val();
s_address_2 = $( 'input#shipping_address_2' ).val();
} else {
s_country = country;
s_state = state;
s_postcode = postcode;
s_city = city;
s_address = address;
s_address_2 = address_2;
s_country = $( '#shipping_country' ).val();
s_state = $( '#shipping_state' ).val();
s_postcode = $( 'input#shipping_postcode' ).val();
s_city = $( '#shipping_city' ).val();
s_address = $( 'input#shipping_address_1' ).val();
s_address_2 = $( 'input#shipping_address_2' ).val();
}
$( '.woocommerce-checkout-payment, .woocommerce-checkout-review-order-table' ).block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
var data = {
security: wc_checkout_params.update_order_review_nonce,
shipping_method: shipping_methods,
payment_method: payment_method,
payment_method: wc_checkout_form.get_payment_method(),
country: country,
state: state,
postcode: postcode,
@ -263,11 +248,35 @@ jQuery( function( $ ) {
post_data: $( 'form.checkout' ).serialize()
};
if ( false !== args.update_shipping_method ) {
var shipping_methods = [];
$( 'select.shipping_method, input[name^="shipping_method"][type="radio"]:checked, input[name^="shipping_method"][type="hidden"]' ).each( function() {
shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();
} );
data.shipping_method = shipping_methods;
}
$( '.woocommerce-checkout-payment, .woocommerce-checkout-review-order-table' ).block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
wc_checkout_form.xhr = $.ajax({
type: 'POST',
url: wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'update_order_review' ),
data: data,
success: function( data ) {
// Reload the page if requested
if ( 'true' === data.reload ) {
window.location.reload();
return;
}
// Always update the fragments
if ( data && data.fragments ) {
$.each( data.fragments, function ( key, value ) {
@ -281,11 +290,6 @@ jQuery( function( $ ) {
var $form = $( 'form.checkout' );
if ( 'true' === data.reload ) {
window.location.reload();
return;
}
$( '.woocommerce-error, .woocommerce-message' ).remove();
// Add new errors
@ -339,6 +343,42 @@ jQuery( function( $ ) {
});
}
// ajaxSetup is global, but we use it to ensure JSON is valid once returned.
$.ajaxSetup( {
dataFilter: function( raw_response, dataType ) {
// We only want to work with JSON
if ( 'json' !== dataType ) {
return raw_response;
}
try {
// check for valid JSON
var data = $.parseJSON( raw_response );
if ( data && 'object' === typeof data ) {
// Valid - return it so it can be parsed by Ajax handler
return raw_response;
}
} catch ( e ) {
// attempt to fix the malformed JSON
var valid_json = raw_response.match( /{"result.*"}/ );
if ( null === valid_json ) {
console.log( 'Unable to fix malformed JSON' );
} else {
console.log( 'Fixed malformed JSON. Original:' );
console.log( raw_response );
raw_response = valid_json[0];
}
}
return raw_response;
}
} );
$.ajax({
type: 'POST',
url: wc_checkout_params.checkout_url,
@ -441,7 +481,7 @@ jQuery( function( $ ) {
$form.before( code );
$form.slideUp();
$( document.body ).trigger( 'update_checkout' );
$( document.body ).trigger( 'update_checkout', { update_shipping_method: false } );
}
},
dataType: 'html'
@ -479,7 +519,7 @@ jQuery( function( $ ) {
if ( code ) {
$( 'form.woocommerce-checkout' ).before( code );
$( document.body ).trigger( 'update_checkout' );
$( document.body ).trigger( 'update_checkout', { update_shipping_method: false } );
// remove coupon code from coupon field
$( 'form.checkout_coupon' ).find( 'input[name="coupon_code"]' ).val( '' );

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1206,6 +1206,12 @@ abstract class WC_Abstract_Order {
return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this );
}
/**
* Get refunds
* @return array
*/
public function get_refunds() { return array(); }
/**
* Return an array of fees within this order.
*
@ -1311,16 +1317,8 @@ abstract class WC_Abstract_Order {
public function get_item_meta_array( $order_item_id ) {
global $wpdb;
// Get cache key - uses cache key wc_orders_cache_prefix to invalidate when needed
$prefix_num = wp_cache_get( 'wc_orders_cache_prefix', 'orders' );
if ( $prefix_num === false ) {
$prefix_num = 1;
wp_cache_set( 'wc_orders_cache_prefix', $prefix_num, 'orders' );
}
$cache_prefix = 'wc_orders_cache_' . $prefix_num . '_';
$cache_key = $cache_prefix . 'item_meta_array_' . $order_item_id;
// Get cache key - uses get_cache_prefix to invalidate when needed
$cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'item_meta_array_' . $order_item_id;
$item_meta_array = wp_cache_get( $cache_key, 'orders' );
if ( false === $item_meta_array ) {
@ -1853,8 +1851,7 @@ abstract class WC_Abstract_Order {
);
}
if ( $fees = $this->get_fees() )
if ( $fees = $this->get_fees() ) {
foreach ( $fees as $id => $fee ) {
if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', $fee['line_total'] + $fee['line_tax'] == 0, $id ) ) {
@ -1876,9 +1873,10 @@ abstract class WC_Abstract_Order {
);
}
}
}
// Tax for tax exclusive prices.
if ( 'excl' == $tax_display ) {
if ( 'excl' === $tax_display ) {
if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
@ -1906,6 +1904,15 @@ abstract class WC_Abstract_Order {
);
}
if ( $refunds = $this->get_refunds() ) {
foreach ( $refunds as $id => $refund ) {
$total_rows[ 'refund_' . $id ] = array(
'label' => $refund->get_refund_reason() ? $refund->get_refund_reason() : __( 'Refund', 'woocommerce' ) . ':',
'value' => wc_price( '-' . $refund->get_refund_amount(), array( 'currency' => $this->get_order_currency() ) )
);
}
}
$total_rows['order_total'] = array(
'label' => __( 'Total:', 'woocommerce' ),
'value' => $this->get_formatted_order_total( $tax_display )
@ -1917,33 +1924,49 @@ abstract class WC_Abstract_Order {
/**
* Output items for display in html emails.
*
* @param bool $show_download_links (default: false).
* @param bool $show_sku (default: false).
* @param bool $show_purchase_note (default: false).
* @param bool $show_image (default: false).
* @param array $image_size (default: array( 32, 32 ).
* @param array $args
* @param bool plain text
* @return string
*/
public function email_order_items_table( $show_download_links = false, $show_sku = false, $show_purchase_note = false, $show_image = false, $image_size = array( 32, 32 ), $plain_text = false ) {
public function email_order_items_table( $args = array(), $deprecated = null, $deprecated = null, $deprecated = null, $deprecated = null, $deprecated = null ) {
ob_start();
$template = $plain_text ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
if ( ! is_null( $deprecated ) ) {
_deprecated_argument( __FUNCTION__, '2.5.0' );
}
$defaults = array(
'show_sku' => false,
'show_image' => false,
'image_size' => array( 32, 32 ),
'plain_text' => false
);
$args = wp_parse_args( $args, $defaults );
$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
wc_get_template( $template, array(
'order' => $this,
'items' => $this->get_items(),
'show_download_links' => $show_download_links,
'show_sku' => $show_sku,
'show_purchase_note' => $show_purchase_note,
'show_image' => $show_image,
'image_size' => $image_size
'order' => $this,
'items' => $this->get_items(),
'show_download_links' => $this->is_download_permitted(),
'show_sku' => $args['show_sku'],
'show_purchase_note' => $this->is_paid(),
'show_image' => $args['show_image'],
'image_size' => $args['image_size'],
) );
return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $this );
}
/**
* Returns if an order has been paid for based on the order status.
* @since 2.5.0
* @return bool
*/
public function is_paid() {
return apply_filters( 'woocommerce_order_is_paid', $this->has_status( apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) ) ), $this );
}
/**
* Checks if product download is permitted.
*
@ -2221,67 +2244,71 @@ abstract class WC_Abstract_Order {
* @param string $new_status Status to change the order to. No internal wc- prefix is required.
* @param string $note (default: '') Optional note to add.
* @param bool $manual is this a manual order status change?
* @return bool Successful change or not
*/
public function update_status( $new_status, $note = '', $manual = false ) {
if ( ! $this->id ) {
return;
return false;
}
// Standardise status names.
$new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status;
$old_status = $this->get_status();
// Only update if they differ - and ensure post_status is a 'wc' status.
if ( $new_status !== $old_status || ! in_array( $this->post_status, array_keys( wc_get_order_statuses() ) ) ) {
// Update the order.
wp_update_post( array( 'ID' => $this->id, 'post_status' => 'wc-' . $new_status ) );
$this->post_status = 'wc-' . $new_status;
$this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), wc_get_order_status_name( $old_status ), wc_get_order_status_name( $new_status ) ) ), 0, $manual );
// Status was changed.
do_action( 'woocommerce_order_status_' . $new_status, $this->id );
do_action( 'woocommerce_order_status_' . $old_status . '_to_' . $new_status, $this->id );
do_action( 'woocommerce_order_status_changed', $this->id, $old_status, $new_status );
switch ( $new_status ) {
case 'completed' :
// Record the sales.
$this->record_product_sales();
// Increase coupon usage counts.
$this->increase_coupon_usage_counts();
// Record the completed date of the order.
update_post_meta( $this->id, '_completed_date', current_time('mysql') );
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
case 'processing' :
case 'on-hold' :
// Record the sales.
$this->record_product_sales();
// Increase coupon usage counts.
$this->increase_coupon_usage_counts();
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
case 'cancelled' :
// If the order is cancelled, restore used coupons.
$this->decrease_coupon_usage_counts();
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
}
// If the statuses are the same there is no need to update, unless the post status is not a valid 'wc' status.
if ( $new_status === $old_status && in_array( $this->post_status, array_keys( wc_get_order_statuses() ) ) ) {
return false;
}
// Update the order.
wp_update_post( array( 'ID' => $this->id, 'post_status' => 'wc-' . $new_status ) );
$this->post_status = 'wc-' . $new_status;
$this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), wc_get_order_status_name( $old_status ), wc_get_order_status_name( $new_status ) ) ), 0, $manual );
// Status was changed.
do_action( 'woocommerce_order_status_' . $new_status, $this->id );
do_action( 'woocommerce_order_status_' . $old_status . '_to_' . $new_status, $this->id );
do_action( 'woocommerce_order_status_changed', $this->id, $old_status, $new_status );
switch ( $new_status ) {
case 'completed' :
// Record the sales.
$this->record_product_sales();
// Increase coupon usage counts.
$this->increase_coupon_usage_counts();
// Record the completed date of the order.
update_post_meta( $this->id, '_completed_date', current_time('mysql') );
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
case 'processing' :
case 'on-hold' :
// Record the sales.
$this->record_product_sales();
// Increase coupon usage counts.
$this->increase_coupon_usage_counts();
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
case 'cancelled' :
// If the order is cancelled, restore used coupons.
$this->decrease_coupon_usage_counts();
// Update reports.
wc_delete_shop_order_transients( $this->id );
break;
}
return true;
}
@ -2381,6 +2408,13 @@ abstract class WC_Abstract_Order {
}
update_post_meta( $this->id, '_recorded_sales', 'yes' );
/**
* Called when sales for an order are recorded
*
* @param int $order_id order id
*/
do_action( 'woocommerce_recorded_sales', $this->id );
}

View File

@ -70,6 +70,9 @@ class WC_Product {
*/
protected $shipping_class_id = 0;
/** @public string The product's total stock, including that of its children. */
public $total_stock;
/**
* Supported features such as 'ajax_add_to_cart'.
* @var array
@ -163,6 +166,17 @@ class WC_Product {
return apply_filters( 'woocommerce_product_supports', in_array( $feature, $this->supports ) ? true : false, $feature, $this );
}
/**
* Return the product ID
*
* @since 2.5.0
* @return int product (post) ID
*/
public function get_id() {
return $this->id;
}
/**
* get_gallery_attachment_ids function.
*
@ -202,10 +216,24 @@ class WC_Product {
/**
* Get total stock.
*
* This is the stock of parent and children combined.
*
* @return int
*/
public function get_total_stock() {
return $this->get_stock_quantity();
if ( empty( $this->total_stock ) ) {
$this->total_stock = max( 0, $this->get_stock_quantity() );
if ( sizeof( $this->get_children() ) > 0 ) {
foreach ( $this->get_children() as $child_id ) {
if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
$stock = get_post_meta( $child_id, '_stock', true );
$this->total_stock += max( 0, wc_stock_amount( $stock ) );
}
}
}
}
return wc_stock_amount( $this->total_stock );
}
/**
@ -436,7 +464,7 @@ class WC_Product {
* @return bool
*/
public function is_virtual() {
return $this->virtual == 'yes' ? true : false;
return apply_filters( 'woocommerce_is_virtual', $this->virtual == 'yes' ? true : false, $this );
}
/**
@ -1044,22 +1072,15 @@ class WC_Product {
}
/**
* Get the average rating of product.
*
* Get the average rating of product. This is calculated once and stored in postmeta.
* @return string
*/
public function get_average_rating() {
$transient_name = 'wc_average_rating_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
if ( false === ( $average_rating = get_transient( $transient_name ) ) ) {
global $wpdb;
$average_rating = '';
$count = $this->get_rating_count();
if ( $count > 0 ) {
global $wpdb;
// No meta date? Do the calculation
if ( ! metadata_exists( 'post', $this->id, '_wc_average_rating' ) ) {
if ( $count = $this->get_rating_count() ) {
$ratings = $wpdb->get_var( $wpdb->prepare("
SELECT SUM(meta_value) FROM $wpdb->commentmeta
LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
@ -1068,28 +1089,28 @@ class WC_Product {
AND comment_approved = '1'
AND meta_value > 0
", $this->id ) );
$average_rating = number_format( $ratings / $count, 2 );
$average = number_format( $ratings / $count, 2, '.', '' );
} else {
$average = 0;
}
set_transient( $transient_name, $average_rating, DAY_IN_SECONDS * 30 );
update_post_meta( $this->id, '_wc_average_rating', $average );
} else {
$average = get_post_meta( $this->id, '_wc_average_rating', true );
}
return $average_rating;
return (string) floatval( $average );
}
/**
* Get the total amount (COUNT) of ratings.
*
* @param int $value Optional. Rating value to get the count for. By default
* returns the count of all rating values.
* @param int $value Optional. Rating value to get the count for. By default returns the count of all rating values.
* @return int
*/
public function get_rating_count( $value = null ) {
$transient_name = 'wc_rating_count_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
global $wpdb;
if ( ! is_array( $counts = get_transient( $transient_name ) ) ) {
global $wpdb;
// No meta date? Do the calculation
if ( ! metadata_exists( 'post', $this->id, '_wc_rating_count' ) ) {
$counts = array();
$raw_counts = $wpdb->get_results( $wpdb->prepare("
SELECT meta_value, COUNT( * ) as meta_value_count FROM $wpdb->commentmeta
@ -1105,7 +1126,9 @@ class WC_Product {
$counts[ $count->meta_value ] = $count->meta_value_count;
}
set_transient( $transient_name, $counts, DAY_IN_SECONDS * 30 );
update_post_meta( $this->id, '_wc_rating_count', $counts );
} else {
$counts = get_post_meta( $this->id, '_wc_rating_count', true );
}
if ( is_null( $value ) ) {
@ -1141,7 +1164,6 @@ class WC_Product {
return apply_filters( 'woocommerce_product_get_rating_html', $rating_html, $rating );
}
/**
* Get the total amount (COUNT) of reviews.
*
@ -1149,13 +1171,10 @@ class WC_Product {
* @return int The total numver of product reviews
*/
public function get_review_count() {
global $wpdb;
$transient_name = 'wc_review_count_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
if ( false === ( $count = get_transient( $transient_name ) ) ) {
global $wpdb;
// No meta date? Do the calculation
if ( ! metadata_exists( 'post', $this->id, '_wc_review_count' ) ) {
$count = $wpdb->get_var( $wpdb->prepare("
SELECT COUNT(*) FROM $wpdb->comments
WHERE comment_parent = 0
@ -1163,13 +1182,14 @@ class WC_Product {
AND comment_approved = '1'
", $this->id ) );
set_transient( $transient_name, $count, DAY_IN_SECONDS * 30 );
update_post_meta( $this->id, '_wc_review_count', $count );
} else {
$count = get_post_meta( $this->id, '_wc_review_count', true );
}
return apply_filters( 'woocommerce_product_review_count', $count, $this );
}
/**
* Returns the upsell product ids.
*
@ -1258,39 +1278,51 @@ class WC_Product {
/**
* Get and return related products.
*
* Notes:
* - Results are cached in a transient for faster queries.
* - To make results appear random, we query and extra 10 products and shuffle them.
* - To ensure we always have enough results, it will check $limit before returning the cached result, if not recalc.
* - This used to rely on transient version to invalidate cache, but to avoid multiple transients we now just expire daily.
* This means if a related product is edited and no longer related, it won't be removed for 24 hours. Acceptable trade-off for performance.
* - Saving a product will flush caches for that product.
*
* @param int $limit (default: 5)
* @return array Array of post IDs
*/
public function get_related( $limit = 5 ) {
$transient_name = 'wc_related_' . $limit . '_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
global $wpdb;
if ( false === ( $related_posts = get_transient( $transient_name ) ) ) {
global $wpdb;
$transient_name = 'wc_related_' . $this->id;
$related_posts = get_transient( $transient_name );
// We want to query related posts if they are not cached, or we don't have enough
if ( false === $related_posts || sizeof( $related_posts ) < $limit ) {
// Related products are found from category and tag
$tags_array = $this->get_related_terms( 'product_tag' );
$cats_array = $this->get_related_terms( 'product_cat' );
// Don't bother if none are set
if ( sizeof( $cats_array ) == 1 && sizeof( $tags_array ) == 1 ) {
if ( 1 === sizeof( $cats_array ) && 1 === sizeof( $tags_array )) {
$related_posts = array();
} else {
// Sanitize
$exclude_ids = array_map( 'absint', array_merge( array( 0, $this->id ), $this->get_upsells() ) );
// Generate query
$query = $this->build_related_query( $cats_array, $tags_array, $exclude_ids, $limit );
// Generate query - but query an extra 10 results to give the appearance of random results
$query = $this->build_related_query( $cats_array, $tags_array, $exclude_ids, $limit + 10 );
// Get the posts
$related_posts = $wpdb->get_col( implode( ' ', $query ) );
}
set_transient( $transient_name, $related_posts, DAY_IN_SECONDS * 30 );
set_transient( $transient_name, $related_posts, DAY_IN_SECONDS );
}
// Randomise the results
shuffle( $related_posts );
return $related_posts;
// Limit the returned results
return array_slice( $related_posts, 0, $limit );
}
/**

View File

@ -5,7 +5,7 @@
* @author WooThemes
* @category Widgets
* @package WooCommerce/Abstracts
* @version 2.3.0
* @version 2.5.0
* @extends WP_Widget
*/
abstract class WC_Widget extends WP_Widget {
@ -128,9 +128,9 @@ abstract class WC_Widget extends WP_Widget {
/**
* update function.
*
* @see WP_Widget->update
* @param array $new_instance
* @param array $old_instance
* @see WP_Widget->update
* @param array $new_instance
* @param array $old_instance
* @return array
*/
public function update( $new_instance, $old_instance ) {
@ -141,12 +141,34 @@ abstract class WC_Widget extends WP_Widget {
return $instance;
}
// Loop settings and get values to save.
foreach ( $this->settings as $key => $setting ) {
if ( ! isset( $setting['type'] ) ) {
continue;
}
if ( isset( $new_instance[ $key ] ) ) {
$instance[ $key ] = sanitize_text_field( $new_instance[ $key ] );
} elseif ( 'checkbox' === $setting['type'] ) {
$instance[ $key ] = 0;
// Format the value based on settings type.
switch ( $setting['type'] ) {
case 'number' :
$instance[ $key ] = absint( $new_instance[ $key ] );
if ( isset( $setting['min'] ) && '' !== $setting['min'] ) {
$instance[ $key ] = max( $instance[ $key ], $setting['min'] );
}
if ( isset( $setting['max'] ) && '' !== $setting['max'] ) {
$instance[ $key ] = min( $instance[ $key ], $setting['max'] );
}
break;
case 'textarea' :
$instance[ $key ] = wp_kses( trim( wp_unslash( $new_instance[ $key ] ) ), wp_kses_allowed_html( 'post' ) );
break;
case 'checkbox' :
$instance[ $key ] = is_null( $new_instance[ $key ] ) ? 0 : 1;
break;
default:
$instance[ $key ] = sanitize_text_field( $new_instance[ $key ] );
break;
}
}
@ -158,7 +180,7 @@ abstract class WC_Widget extends WP_Widget {
/**
* form function.
*
* @see WP_Widget->form
* @see WP_Widget->form
* @param array $instance
*/
public function form( $instance ) {
@ -169,6 +191,7 @@ abstract class WC_Widget extends WP_Widget {
foreach ( $this->settings as $key => $setting ) {
$class = isset( $setting['class'] ) ? $setting['class'] : '';
$value = isset( $instance[ $key ] ) ? $instance[ $key ] : $setting['std'];
switch ( $setting['type'] ) {
@ -177,7 +200,7 @@ abstract class WC_Widget extends WP_Widget {
?>
<p>
<label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
<input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
</p>
<?php
break;
@ -186,7 +209,7 @@ abstract class WC_Widget extends WP_Widget {
?>
<p>
<label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" />
<input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" />
</p>
<?php
break;
@ -195,7 +218,7 @@ abstract class WC_Widget extends WP_Widget {
?>
<p>
<label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
<select class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>">
<select class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>">
<?php foreach ( $setting['options'] as $option_key => $option_value ) : ?>
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $option_key, $value ); ?>><?php echo esc_html( $option_value ); ?></option>
<?php endforeach; ?>
@ -204,10 +227,22 @@ abstract class WC_Widget extends WP_Widget {
<?php
break;
case 'textarea' :
?>
<p>
<label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
<textarea class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" cols="20" rows="3"><?php echo esc_textarea( $value ); ?></textarea>
<?php if ( isset( $setting['desc'] ) ) : ?>
<small><?php echo esc_html( $setting['desc'] ); ?></small>
<?php endif; ?>
</p>
<?php
break;
case 'checkbox' :
?>
<p>
<input id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?> />
<input class="checkbox <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?> />
<label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
</p>
<?php

View File

@ -2,10 +2,10 @@
/**
* Addons Page
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.1.0
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -17,6 +17,47 @@ if ( ! defined( 'ABSPATH' ) ) {
*/
class WC_Admin_Addons {
/**
* Handles the outputting of a contextually aware Storefront link (points to child themes if Storefront is already active).
*/
public static function output_storefront_button() {
$url = 'http://www.woothemes.com/storefront/';
$text = __( 'View more about Storefront', 'woocommerce' );
$template = get_option( 'template' );
$stylesheet = get_option( 'stylesheet' );
$utm_content = 'hasstorefront';
// If we're using Storefront with a child theme.
if ( 'storefront' == $template && 'storefront' != $stylesheet ) {
$url = 'http:///www.woothemes.com/product-category/themes/storefront-child-theme-themes/';
$text = __( 'View more Storefront child themes', 'woocommerce' );
$utm_content = 'hasstorefrontchildtheme';
}
// If we're using Storefront without a child theme.
if ( 'storefront' == $template && 'storefront' == $stylesheet ) {
$url = 'http:///www.woothemes.com/product-category/themes/storefront-child-theme-themes/';
$text = __( 'Need a fresh look? Try Storefront child themes', 'woocommerce' );
$utm_content = 'nostorefrontchildtheme';
}
// If we're not using Storefront at all.
if ( 'storefront' != $template && 'storefront' != $stylesheet ) {
$url = 'http://www.woothemes.com/storefront/';
$text = __( 'Need a theme? Try Storefront', 'woocommerce' );
$utm_content = 'nostorefront';
}
$url = add_query_arg( array(
'utm_source' => 'product',
'utm_medium' => 'upsell',
'utm_campaign' => 'wcaddons',
'utm_content' => $utm_content,
), $url );
echo '<a href="' . esc_url( $url ) . '" class="add-new-h2">' . esc_html( $text ) . '</a>' . "\n";
}
/**
* Handles output of the reports page in admin.
*/

View File

@ -244,7 +244,7 @@ class WC_Admin_Attributes {
?>
<div class="wrap woocommerce">
<div class="icon32 icon32-attributes" id="icon-woocommerce"><br/></div>
<h2><?php _e( 'Edit Attribute', 'woocommerce' ) ?></h2>
<h1><?php _e( 'Edit Attribute', 'woocommerce' ) ?></h1>
<?php
@ -345,7 +345,7 @@ class WC_Admin_Attributes {
?>
<div class="wrap woocommerce">
<div class="icon32 icon32-attributes" id="icon-woocommerce"><br/></div>
<h2><?php _e( 'Attributes', 'woocommerce' ); ?></h2>
<h1><?php _e( 'Attributes', 'woocommerce' ); ?></h1>
<br class="clear" />
<div id="col-container">
<div id="col-right">

View File

@ -159,7 +159,7 @@ class WC_Admin_Help {
'id' => 'woocommerce_101_tab',
'title' => __( 'WooCommerce 101', 'woocommerce' ),
'content' =>
'<h2><a href="http://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommerce&utm_medium=Wizard&utm_content=Videos&utm_campaign=Onboarding">' . __( 'WooCommerce 101', 'woocommerce' ) . '</a> &ndash; ' . esc_html( $video_map[ $video_key ]['title'] ) . '</h2>' .
'<h2><a href="http://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Videos&utm_campaign=Onboarding">' . __( 'WooCommerce 101', 'woocommerce' ) . '</a> &ndash; ' . esc_html( $video_map[ $video_key ]['title'] ) . '</h2>' .
'<iframe src="' . esc_url( $video_map[ $video_key ]['url'] ) . '" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" allowfullscreen mozallowfullscreen webkitallowfullscreen oallowfullscreen msallowfullscreen width="480" height="298"></iframe>'
) );
}
@ -170,7 +170,7 @@ class WC_Admin_Help {
'content' =>
'<h2>' . __( 'Documentation', 'woocommerce' ) . '</h2>' .
'<p>' . __( 'Should you need help understanding, using, or extending WooCommerce, please read our documentation. You will find all kinds of resources including snippets, tutorials and much more.' , 'woocommerce' ) . '</p>' .
'<p><a href="' . 'http://docs.woothemes.com/documentation/plugins/woocommerce/' . '" class="button button-primary">' . __( 'WooCommerce Documentation', 'woocommerce' ) . '</a> <a href="' . 'http://docs.woothemes.com/wc-apidocs/' . '" class="button">' . __( 'Developer API Docs', 'woocommerce' ) . '</a></p>'
'<p><a href="' . 'http://docs.woothemes.com/documentation/plugins/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Docs&utm_campaign=Onboarding' . '" class="button button-primary">' . __( 'WooCommerce Documentation', 'woocommerce' ) . '</a> <a href="' . 'http://docs.woothemes.com/wc-apidocs/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=APIDocs&utm_campaign=Onboarding' . '" class="button">' . __( 'Developer API Docs', 'woocommerce' ) . '</a></p>'
) );
@ -179,9 +179,9 @@ class WC_Admin_Help {
'title' => __( 'Support', 'woocommerce' ),
'content' =>
'<h2>' . __( 'Support', 'woocommerce' ) . '</h2>' .
'<p>' . sprintf( __( 'After %sreading the documentation%s, for further assistance you can use the %scommunity forums%s on WordPress.org to talk with other users. If however you are a WooThemes customer, or need help with premium add-ons sold by WooThemes, please %suse our helpdesk%s.', 'woocommerce' ), '<a href="http://docs.woothemes.com/documentation/plugins/woocommerce/">', '</a>', '<a href="https://wordpress.org/support/plugin/woocommerce">', '</a>', '<a href="http://support.woothemes.com">', '</a>' ) . '</p>' .
'<p>' . sprintf( __( 'After %sreading the documentation%s, for further assistance you can use the %scommunity forums%s on WordPress.org to talk with other users. If however you are a WooThemes customer, or need help with premium add-ons sold by WooThemes, please %suse our helpdesk%s.', 'woocommerce' ), '<a href="http://docs.woothemes.com/documentation/plugins/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Docs&utm_campaign=Onboarding">', '</a>', '<a href="https://wordpress.org/support/plugin/woocommerce">', '</a>', '<a href="http://www.woothemes.com/my-account/tickets/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Tickets&utm_campaign=Onboarding">', '</a>' ) . '</p>' .
'<p>' . __( 'Before asking for help we recommend checking the system status page to identify any problems with your configuration.', 'woocommerce' ) . '</p>' .
'<p><a href="' . admin_url( 'admin.php?page=wc-status' ) . '" class="button button-primary">' . __( 'System Status', 'woocommerce' ) . '</a> <a href="' . 'https://wordpress.org/support/plugin/woocommerce' . '" class="button">' . __( 'WordPress.org Forums', 'woocommerce' ) . '</a> <a href="' . 'http://support.woothemes.com' . '" class="button">' . __( 'WooThemes Customer Support', 'woocommerce' ) . '</a></p>'
'<p><a href="' . admin_url( 'admin.php?page=wc-status' ) . '" class="button button-primary">' . __( 'System Status', 'woocommerce' ) . '</a> <a href="' . 'https://wordpress.org/support/plugin/woocommerce' . '" class="button">' . __( 'WordPress.org Forums', 'woocommerce' ) . '</a> <a href="' . 'http://www.woothemes.com/my-account/tickets/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Tickets&utm_campaign=Onboarding' . '" class="button">' . __( 'WooThemes Customer Support', 'woocommerce' ) . '</a></p>'
) );
$screen->add_help_tab( array(
@ -190,7 +190,7 @@ class WC_Admin_Help {
'content' =>
'<h2>' . __( 'Education', 'woocommerce' ) . '</h2>' .
'<p>' . __( 'If you would like to learn about using WooCommerce from an expert, consider following a WooCommerce course ran by one of our educational partners.', 'woocommerce' ) . '</p>' .
'<p><a href="' . 'http://www.woothemes.com/educational-partners/?utm_source=WooCommerce&utm_medium=Wizard&utm_content=Partners&utm_campaign=Onboarding' . '" class="button button-primary">' . __( 'View Education Partners', 'woocommerce' ) . '</a></p>'
'<p><a href="' . 'http://www.woothemes.com/educational-partners/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=EduPartners&utm_campaign=Onboarding' . '" class="button button-primary">' . __( 'View Education Partners', 'woocommerce' ) . '</a></p>'
) );
$screen->add_help_tab( array(
@ -215,11 +215,11 @@ class WC_Admin_Help {
$screen->set_help_sidebar(
'<p><strong>' . __( 'For more information:', 'woocommerce' ) . '</strong></p>' .
'<p><a href="' . 'http://www.woothemes.com/woocommerce/' . '" target="_blank">' . __( 'About WooCommerce', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'http://www.woothemes.com/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WooCommerceProductPage&utm_campaign=Onboarding' . '" target="_blank">' . __( 'About WooCommerce', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'http://wordpress.org/extend/plugins/woocommerce/' . '" target="_blank">' . __( 'WordPress.org Project', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://github.com/woothemes/woocommerce' . '" target="_blank">' . __( 'Github Project', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'http://www.woothemes.com/product-category/themes/woocommerce/' . '" target="_blank">' . __( 'Official Themes', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'http://www.woothemes.com/product-category/woocommerce-extensions/' . '" target="_blank">' . __( 'Official Extensions', 'woocommerce' ) . '</a></p>'
'<p><a href="' . 'http://www.woothemes.com/product-category/themes/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WCThemes&utm_campaign=Onboarding' . '" target="_blank">' . __( 'Official Themes', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'http://www.woothemes.com/product-category/woocommerce-extensions/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WCExtensions&utm_campaign=Onboarding' . '" target="_blank">' . __( 'Official Extensions', 'woocommerce' ) . '</a></p>'
);
}

View File

@ -5,11 +5,11 @@
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.1.0
* @version 2.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
if ( ! class_exists( 'WC_Admin_Importers' ) ) :
@ -70,7 +70,7 @@ class WC_Admin_Importers {
return;
}
$id = (int) $_POST['import_id'];
$id = absint( $_POST['import_id'] );
$file = get_attached_file( $id );
$parser = new WXR_Parser();
$import_data = $parser->parse( $file );
@ -79,40 +79,36 @@ class WC_Admin_Importers {
$posts = $import_data['posts'];
if ( $posts && sizeof( $posts ) > 0 ) {
foreach ( $posts as $post ) {
if ( $post['post_type'] == 'product' ) {
if ( $post['terms'] && sizeof( $post['terms'] ) > 0 ) {
if ( 'product' === $post['post_type'] ) {
if ( ! empty( $post['terms'] ) ) {
foreach ( $post['terms'] as $term ) {
$domain = $term['domain'];
if ( strstr( $domain, 'pa_' ) ) {
// Make sure it exists!
if ( ! taxonomy_exists( $domain ) ) {
$nicename = strtolower( sanitize_title( str_replace( 'pa_', '', $domain ) ) );
$exists_in_db = $wpdb->get_var( $wpdb->prepare( "SELECT attribute_id FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies WHERE attribute_name = %s;", $nicename ) );
if ( strstr( $term['domain'], 'pa_' ) ) {
if ( ! taxonomy_exists( $term['domain'] ) ) {
$attribute_name = wc_sanitize_taxonomy_name( str_replace( 'pa_', '', $term['domain'] ) );
// Create the taxonomy
if ( ! $exists_in_db ) {
$wpdb->insert( $wpdb->prefix . "woocommerce_attribute_taxonomies", array( 'attribute_name' => $nicename, 'attribute_type' => 'select', 'attribute_orderby' => 'menu_order', 'attribute_public' => 0 ), array( '%s', '%s', '%s' ) );
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
$attribute = array(
'attribute_label' => $attribute_name,
'attribute_name' => $attribute_name,
'attribute_type' => 'select',
'attribute_orderby' => 'menu_order',
'attribute_public' => 0
);
$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );
delete_transient( 'wc_attribute_taxonomies' );
}
// Register the taxonomy now so that the import works!
register_taxonomy(
$domain,
apply_filters( 'woocommerce_taxonomy_objects_' . $domain, array( 'product' ) ),
apply_filters( 'woocommerce_taxonomy_args_' . $domain, array(
$term['domain'],
apply_filters( 'woocommerce_taxonomy_objects_' . $term['domain'], array( 'product' ) ),
apply_filters( 'woocommerce_taxonomy_args_' . $term['domain'], array(
'hierarchical' => true,
'show_ui' => false,
'query_var' => true,
'rewrite' => false,
'show_ui' => false,
'query_var' => true,
'rewrite' => false,
) )
);
}

View File

@ -84,7 +84,7 @@ class WC_Admin_Meta_Boxes {
if ( ! empty( $errors ) ) {
echo '<div id="woocommerce_errors" class="error">';
echo '<div id="woocommerce_errors" class="error notice is-dismissible">';
foreach ( $errors as $error ) {
echo '<p>' . wp_kses_post( $error ) . '</p>';

View File

@ -1049,7 +1049,7 @@ class WC_Admin_Post_Types {
// Save fields
if ( isset( $_REQUEST['_sku'] ) ) {
$sku = get_post_meta( $post_id, '_sku', true );
$new_sku = wc_clean( stripslashes( $_REQUEST['_sku'] ) );
$new_sku = wc_clean( $_REQUEST['_sku'] );
if ( $new_sku !== $sku ) {
if ( ! empty( $new_sku ) ) {
@ -1264,7 +1264,16 @@ class WC_Admin_Post_Types {
}
// Handle price - remove dates and set to lowest
if ( $product->is_type( 'simple' ) || $product->is_type( 'external' ) ) {
$change_price_product_types = apply_filters( 'woocommerce_bulk_edit_save_price_product_types', array( 'simple', 'external' ) );
$can_product_type_change_price = false;
foreach ( $change_price_product_types as $product_type ) {
if ( $product->is_type( $product_type ) ) {
$can_product_type_change_price = true;
break;
}
}
if ( $can_product_type_change_price ) {
$price_changed = false;

View File

@ -757,10 +757,10 @@ class WC_Admin_Setup_Wizard {
<div class="wc-setup-next-steps-last">
<h2><?php _e( 'Learn More', 'woocommerce' ); ?></h2>
<ul>
<li class="video-walkthrough"><a href="http://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommerce&amp;utm_medium=Wizard&amp;utm_content=Videos&amp;utm_campaign=Onboarding"><?php _e( 'Watch the WC 101 video walkthroughs', 'woocommerce' ); ?></a></li>
<li class="newsletter"><a href="http://www.woothemes.com/woocommerce-onboarding-email/?utm_source=WooCommerce&amp;utm_medium=Wizard&amp;utm_content=Newsletter&amp;utm_campaign=Onboarding"><?php _e( 'Get eCommerce advice in your inbox', 'woocommerce' ); ?></a></li>
<li class="video-walkthrough"><a href="http://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Videos&amp;utm_campaign=Onboarding"><?php _e( 'Watch the WC 101 video walkthroughs', 'woocommerce' ); ?></a></li>
<li class="newsletter"><a href="http://www.woothemes.com/woocommerce-onboarding-email/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Newsletter&amp;utm_campaign=Onboarding"><?php _e( 'Get eCommerce advice in your inbox', 'woocommerce' ); ?></a></li>
<li class="sidekick"><a href="http://www.woothemes.com/sidekick/"><?php _e( 'Follow Sidekick interactive walkthroughs', 'woocommerce' ); ?></a></li>
<li class="learn-more"><a href="http://docs.woothemes.com/documentation/plugins/woocommerce/getting-started/?utm_source=WooCommerce&amp;utm_medium=Wizard&amp;utm_content=Docs&amp;utm_campaign=Onboarding"><?php _e( 'Read more about getting started', 'woocommerce' ); ?></a></li>
<li class="learn-more"><a href="http://docs.woothemes.com/documentation/plugins/woocommerce/getting-started/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Docs&amp;utm_campaign=Onboarding"><?php _e( 'Read more about getting started', 'woocommerce' ); ?></a></li>
</ul>
</div>
</div>

View File

@ -109,8 +109,8 @@ class WC_Admin_Status {
case 'delete_taxes' :
$wpdb->query( "TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rates" );
$wpdb->query( "TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rate_locations" );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
echo '<div class="updated"><p>' . __( 'Tax rates successfully deleted', 'woocommerce' ) . '</p></div>';
break;

View File

@ -151,18 +151,26 @@ class WC_Admin_Webhooks {
// Topic
$this->update_topic( $webhook );
// Ping the webhook at the first time that is activated
$peding_delivery = get_post_meta( $webhook->id, '_webhook_pending_delivery', true );
if ( isset( $_POST['webhook_status'] ) && 'active' === $_POST['webhook_status'] && $peding_delivery ) {
$webhook->deliver_ping();
}
// Run actions
do_action( 'woocommerce_webhook_options_save', $webhook->id );
delete_transient( 'woocommerce_webhook_ids' );
// Ping the webhook at the first time that is activated
$pending_delivery = get_post_meta( $webhook->id, '_webhook_pending_delivery', true );
if ( isset( $_POST['webhook_status'] ) && 'active' === $_POST['webhook_status'] && $pending_delivery ) {
$result = $webhook->deliver_ping();
if ( is_wp_error( $result ) ) {
// Redirect to webhook edit page to avoid settings save actions
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&error=' . urlencode( $result->get_error_message() ) ) );
exit();
}
}
// Redirect to webhook edit page to avoid settings save actions
wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&updated=1' ) );
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&updated=1' ) );
exit();
}
@ -382,6 +390,10 @@ class WC_Admin_Webhooks {
if ( isset( $_GET['created'] ) ) {
WC_Admin_Settings::add_message( __( 'Webhook created successfully.', 'woocommerce' ) );
}
if ( isset( $_GET['error'] ) ) {
WC_Admin_Settings::add_error( wc_clean( $_GET['error'] ) );
}
}
/**

View File

@ -190,7 +190,7 @@ class WC_Tax_Rate_Importer extends WP_Importer {
*/
public function header() {
echo '<div class="wrap"><div class="icon32 icon32-woocommerce-importer" id="icon-woocommerce"><br></div>';
echo '<h2>' . __( 'Import Tax Rates', 'woocommerce' ) . '</h2>';
echo '<h1>' . __( 'Import Tax Rates', 'woocommerce' ) . '</h1>';
}
/**

View File

@ -81,10 +81,10 @@ class WC_Meta_Box_Coupon_Data {
echo '<div class="options_group">';
// minimum spend
woocommerce_wp_text_input( array( 'id' => 'minimum_amount', 'label' => __( 'Minimum spend', 'woocommerce' ), 'placeholder' => __( 'No minimum', 'woocommerce' ), 'description' => __( 'This field allows you to set the minimum subtotal needed to use the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
woocommerce_wp_text_input( array( 'id' => 'minimum_amount', 'label' => __( 'Minimum spend', 'woocommerce' ), 'placeholder' => __( 'No minimum', 'woocommerce' ), 'description' => __( 'This field allows you to set the minimum spend (subtotal, including taxes) allowed to use the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
// maximum spend
woocommerce_wp_text_input( array( 'id' => 'maximum_amount', 'label' => __( 'Maximum spend', 'woocommerce' ), 'placeholder' => __( 'No maximum', 'woocommerce' ), 'description' => __( 'This field allows you to set the maximum subtotal allowed when using the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
woocommerce_wp_text_input( array( 'id' => 'maximum_amount', 'label' => __( 'Maximum spend', 'woocommerce' ), 'placeholder' => __( 'No maximum', 'woocommerce' ), 'description' => __( 'This field allows you to set the maximum spend (subtotal, including taxes) allowed when using the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
// Individual use
woocommerce_wp_checkbox( array( 'id' => 'individual_use', 'label' => __( 'Individual use only', 'woocommerce' ), 'description' => __( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woocommerce' ) ) );
@ -268,6 +268,9 @@ class WC_Meta_Box_Coupon_Data {
update_post_meta( $post_id, 'maximum_amount', $maximum_amount );
update_post_meta( $post_id, 'customer_email', $customer_email );
// Clear cache
WC_Cache_Helper::incr_cache_prefix( 'coupons' );
do_action( 'woocommerce_coupon_options_save', $post_id );
}
}

View File

@ -793,14 +793,6 @@ class WC_Meta_Box_Product_Data {
update_post_meta( $post_id, '_virtual', $is_virtual );
// Update post meta
if ( isset( $_POST['_regular_price'] ) ) {
update_post_meta( $post_id, '_regular_price', ( $_POST['_regular_price'] === '' ) ? '' : wc_format_decimal( $_POST['_regular_price'] ) );
}
if ( isset( $_POST['_sale_price'] ) ) {
update_post_meta( $post_id, '_sale_price', ( $_POST['_sale_price'] === '' ? '' : wc_format_decimal( $_POST['_sale_price'] ) ) );
}
if ( isset( $_POST['_tax_status'] ) ) {
update_post_meta( $post_id, '_tax_status', wc_clean( $_POST['_tax_status'] ) );
}
@ -850,14 +842,12 @@ class WC_Meta_Box_Product_Data {
// Unique SKU
$sku = get_post_meta( $post_id, '_sku', true );
$new_sku = wc_clean( stripslashes( $_POST['_sku'] ) );
$new_sku = wc_clean( $_POST['_sku'] );
if ( '' == $new_sku ) {
update_post_meta( $post_id, '_sku', '' );
} elseif ( $new_sku !== $sku ) {
if ( ! empty( $new_sku ) ) {
$unique_sku = wc_product_has_unique_sku( $post_id, $new_sku );
if ( ! $unique_sku ) {
@ -997,22 +987,17 @@ class WC_Meta_Box_Product_Data {
update_post_meta( $post_id, '_price', '' );
} else {
$date_from = isset( $_POST['_sale_price_dates_from'] ) ? wc_clean( $_POST['_sale_price_dates_from'] ) : '';
$date_to = isset( $_POST['_sale_price_dates_to'] ) ? wc_clean( $_POST['_sale_price_dates_to'] ) : '';
$regular_price = isset( $_POST['_regular_price'] ) ? wc_clean( $_POST['_regular_price'] ) : '';
$sale_price = isset( $_POST['_sale_price'] ) ? wc_clean( $_POST['_sale_price'] ) : '';
$date_from = isset( $_POST['_sale_price_dates_from'] ) ? wc_clean( $_POST['_sale_price_dates_from'] ) : '';
$date_to = isset( $_POST['_sale_price_dates_to'] ) ? wc_clean( $_POST['_sale_price_dates_to'] ) : '';
update_post_meta( $post_id, '_regular_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) );
update_post_meta( $post_id, '_sale_price', '' === $sale_price ? '' : wc_format_decimal( $sale_price ) );
// Dates
if ( $date_from ) {
update_post_meta( $post_id, '_sale_price_dates_from', strtotime( $date_from ) );
} else {
update_post_meta( $post_id, '_sale_price_dates_from', '' );
}
if ( $date_to ) {
update_post_meta( $post_id, '_sale_price_dates_to', strtotime( $date_to ) );
} else {
update_post_meta( $post_id, '_sale_price_dates_to', '' );
}
update_post_meta( $post_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' );
update_post_meta( $post_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' );
if ( $date_to && ! $date_from ) {
$date_from = date( 'Y-m-d' );
@ -1020,18 +1005,16 @@ class WC_Meta_Box_Product_Data {
}
// Update price if on sale
if ( '' !== $_POST['_sale_price'] && '' == $date_to && '' == $date_from ) {
update_post_meta( $post_id, '_price', wc_format_decimal( $_POST['_sale_price'] ) );
if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) {
update_post_meta( $post_id, '_price', wc_format_decimal( $sale_price ) );
} elseif ( '' !== $sale_price && $date_from && strtotime( $date_from ) <= strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
update_post_meta( $post_id, '_price', wc_format_decimal( $sale_price ) );
} else {
update_post_meta( $post_id, '_price', ( $_POST['_regular_price'] === '' ) ? '' : wc_format_decimal( $_POST['_regular_price'] ) );
}
if ( '' !== $_POST['_sale_price'] && $date_from && strtotime( $date_from ) <= strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
update_post_meta( $post_id, '_price', wc_format_decimal( $_POST['_sale_price'] ) );
update_post_meta( $post_id, '_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) );
}
if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
update_post_meta( $post_id, '_price', ( $_POST['_regular_price'] === '' ) ? '' : wc_format_decimal( $_POST['_regular_price'] ) );
update_post_meta( $post_id, '_price', '' === $regular_price ? '' : wc_format_decimal( $regular_price ) );
update_post_meta( $post_id, '_sale_price_dates_from', '' );
update_post_meta( $post_id, '_sale_price_dates_to', '' );
}
@ -1324,7 +1307,15 @@ class WC_Meta_Box_Product_Data {
} else {
$wpdb->update( $wpdb->posts, array( 'post_status' => $post_status, 'post_title' => $variation_post_title, 'menu_order' => $variable_menu_order[ $i ] ), array( 'ID' => $variation_id ) );
$modified_date = date_i18n( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
$wpdb->update( $wpdb->posts, array(
'post_status' => $post_status,
'post_title' => $variation_post_title,
'menu_order' => $variable_menu_order[ $i ],
'post_modified' => $modified_date,
'post_modified_gmt' => get_gmt_from_date( $modified_date )
), array( 'ID' => $variation_id ) );
clean_post_cache( $variation_id );
@ -1339,12 +1330,11 @@ class WC_Meta_Box_Product_Data {
// Unique SKU
$sku = get_post_meta( $variation_id, '_sku', true );
$new_sku = wc_clean( stripslashes( $variable_sku[ $i ] ) );
$new_sku = wc_clean( $variable_sku[ $i ] );
if ( '' == $new_sku ) {
update_post_meta( $variation_id, '_sku', '' );
} elseif ( $new_sku !== $sku ) {
if ( ! empty( $new_sku ) ) {
$unique_sku = wc_product_has_unique_sku( $variation_id, $new_sku );

View File

@ -38,14 +38,33 @@ class WC_Meta_Box_Product_Images {
$attachments = array_filter( explode( ',', $product_image_gallery ) );
$update_meta = false;
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment_id ) {
$attachment = wp_get_attachment_image( $attachment_id, 'thumbnail' );
// if attachment is empty skip
if ( empty( $attachment ) ) {
$update_meta = true;
continue;
}
echo '<li class="image" data-attachment_id="' . esc_attr( $attachment_id ) . '">
' . wp_get_attachment_image( $attachment_id, 'thumbnail' ) . '
' . $attachment . '
<ul class="actions">
<li><a href="#" class="delete tips" data-tip="' . esc_attr__( 'Delete image', 'woocommerce' ) . '">' . __( 'Delete', 'woocommerce' ) . '</a></li>
</ul>
</li>';
// rebuild ids to be saved
$updated_gallery_ids[] = $attachment_id;
}
// need to update product meta to set new gallery ids
if ( $update_meta ) {
update_post_meta( $post->ID, '_product_image_gallery', implode( ',', $updated_gallery_ids ) );
}
}
?>

View File

@ -242,7 +242,8 @@ extract( $variation_data );
do_action( 'woocommerce_product_options_tax', $loop, $variation_data, $variation );
?>
<?php endif; ?>
</div>
<div>
<p class="form-row form-row-full">
<label><?php _e( 'Variation Description:', 'woocommerce' ); ?></label>
<textarea name="variable_description[<?php echo $loop; ?>]" rows="3" style="width:100%;"><?php echo isset( $variation_data['_variation_description'] ) ? esc_textarea( $variation_data['_variation_description'] ) : ''; ?></textarea>

View File

@ -97,7 +97,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
$this->save_tax_rates();
}
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_tax_rates_%') OR `option_name` LIKE ('_transient_timeout_wc_tax_rates_%')" );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
}
/**

View File

@ -16,11 +16,11 @@ $theme = wp_get_theme();
<div class="wrap woocommerce wc_addons_wrap">
<div class="icon32 icon32-posts-product" id="icon-woocommerce"><br /></div>
<h2>
<h1>
<?php _e( 'WooCommerce Add-ons/Extensions', 'woocommerce' ); ?>
<a href="http://www.woothemes.com/product-category/woocommerce-extensions/" class="add-new-h2"><?php _e( 'Browse all extensions', 'woocommerce' ); ?></a>
<a href="http://www.woothemes.com/storefront/" class="add-new-h2"><?php _e( 'Need a theme? Try Storefront', 'woocommerce' ); ?></a>
</h2>
<?php WC_Admin_Addons::output_storefront_button(); ?>
</h1>
<?php if ( $addons ) : ?>
<ul class="subsubsub">
<?php

View File

@ -66,6 +66,11 @@ if ( ! defined( 'ABSPATH' ) ) {
<td><?php
$memory = wc_let_to_num( WP_MEMORY_LIMIT );
if ( function_exists( 'memory_get_usage' ) ) {
$system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
$memory = max( $memory, $system_memory );
}
if ( $memory < 67108864 ) {
echo '<mark class="error">' . sprintf( __( '%s - We recommend setting memory to at least 64MB. See: <a href="%s" target="_blank">Increasing memory allocated to PHP</a>', 'woocommerce' ), size_format( $memory ), 'http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP' ) . '</mark>';
} else {

View File

@ -32,14 +32,14 @@ if ( ! defined( 'ABSPATH' ) ) {
<label>
<span class="title"><?php _e( 'Price', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_regular_price" class="text regular_price" placeholder="<?php esc_attr_e( 'Regular Price', 'woocommerce' ); ?>" value="">
<input type="text" name="_regular_price" class="text wc_input_price regular_price" placeholder="<?php esc_attr_e( 'Regular Price', 'woocommerce' ); ?>" value="">
</span>
</label>
<br class="clear" />
<label>
<span class="title"><?php _e( 'Sale', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_sale_price" class="text sale_price" placeholder="<?php esc_attr_e( 'Sale Price', 'woocommerce' ); ?>" value="">
<input type="text" name="_sale_price" class="text wc_input_price sale_price" placeholder="<?php esc_attr_e( 'Sale Price', 'woocommerce' ); ?>" value="">
</span>
</label>
<br class="clear" />
@ -108,9 +108,9 @@ if ( ! defined( 'ABSPATH' ) ) {
<div>
<span class="title"><?php _e( 'L/W/H', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_length" class="text length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" value="">
<input type="text" name="_width" class="text width" placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" value="">
<input type="text" name="_height" class="text height" placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" value="">
<input type="text" name="_length" class="text wc_input_decimal length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" value="">
<input type="text" name="_width" class="text wc_input_decimal width" placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" value="">
<input type="text" name="_height" class="text wc_input_decimal height" placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" value="">
</span>
</div>
</div>

View File

@ -186,9 +186,10 @@ class WC_API_Authentication {
/**
* Get user by ID
*
* @since 2.4.0
* @param int $user_id
* @since 2.4.0
* @param int $user_id
* @return WC_User
* @throws Exception
*/
private function get_user_by_id( $user_id ) {
$user = get_user_by( 'id', $user_id );
@ -332,7 +333,7 @@ class WC_API_Authentication {
$valid_window = 15 * 60; // 15 minute window
if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) {
throw new Exception( __( 'Invalid timestamp', 'woocommerce' ) );
throw new Exception( __( 'Invalid timestamp', 'woocommerce' ), 401 );
}
$used_nonces = maybe_unserialize( $keys['nonces'] );

View File

@ -131,27 +131,32 @@ class WC_API_Orders extends WC_API_Resource {
/**
* Get the order for the given ID
* Get the order for the given ID.
*
* @since 2.1
* @param int $id the order ID
* @param array $fields
* @param array $filter
* @param int $id The order ID.
* @param array $fields Request fields.
* @param array $filter Request filters.
* @return array
*/
public function get_order( $id, $fields = null, $filter = array() ) {
// ensure order ID is valid & user has permission to read
// Ensure order ID is valid & user has permission to read.
$id = $this->validate_request( $id, $this->post_type, 'read' );
if ( is_wp_error( $id ) ) {
return $id;
}
// Get the decimal precession
// Get the decimal precession.
$dp = ( isset( $filter['dp'] ) ? intval( $filter['dp'] ) : 2 );
$order = wc_get_order( $id );
$order_post = get_post( $id );
$expand = array();
if ( ! empty( $filter['expand'] ) ) {
$expand = explode( ',', $filter['expand'] );
}
$order_data = array(
'id' => $order->id,
@ -211,9 +216,8 @@ class WC_API_Orders extends WC_API_Resource {
'coupon_lines' => array(),
);
// add line items
// Add line items.
foreach ( $order->get_items() as $item_id => $item ) {
$product = $order->get_product_from_item( $item );
$product_id = null;
$product_sku = null;
@ -228,7 +232,7 @@ class WC_API_Orders extends WC_API_Resource {
$item_meta = array();
$hideprefix = ( isset( $filter['all_item_meta'] ) && $filter['all_item_meta'] === 'true' ) ? null : '_';
$hideprefix = ( isset( $filter['all_item_meta'] ) && 'true' === $filter['all_item_meta'] ) ? null : '_';
foreach ( $meta->get_formatted( $hideprefix ) as $meta_key => $formatted_meta ) {
$item_meta[] = array(
@ -238,7 +242,7 @@ class WC_API_Orders extends WC_API_Resource {
);
}
$order_data['line_items'][] = array(
$line_item = array(
'id' => $item_id,
'subtotal' => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ),
'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ),
@ -252,11 +256,20 @@ class WC_API_Orders extends WC_API_Resource {
'sku' => $product_sku,
'meta' => $item_meta,
);
if ( in_array( 'products', $expand ) ) {
$_product_data = WC()->api->WC_API_Products->get_product( $product_id );
if ( isset( $_product_data['product'] ) ) {
$line_item['product_data'] = $_product_data['product'];
}
}
$order_data['line_items'][] = $line_item;
}
// add shipping
// Add shipping.
foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) {
$order_data['shipping_lines'][] = array(
'id' => $shipping_item_id,
'method_id' => $shipping_item['method_id'],
@ -265,10 +278,9 @@ class WC_API_Orders extends WC_API_Resource {
);
}
// add taxes
// Add taxes.
foreach ( $order->get_tax_totals() as $tax_code => $tax ) {
$order_data['tax_lines'][] = array(
$tax_line = array(
'id' => $tax->id,
'rate_id' => $tax->rate_id,
'code' => $tax_code,
@ -276,11 +288,20 @@ class WC_API_Orders extends WC_API_Resource {
'total' => wc_format_decimal( $tax->amount, $dp ),
'compound' => (bool) $tax->is_compound,
);
if ( in_array( 'taxes', $expand ) ) {
$_rate_data = WC()->api->WC_API_Taxes->get_tax( $tax->rate_id );
if ( isset( $_rate_data['tax'] ) ) {
$tax_line['rate_data'] = $_rate_data['tax'];
}
}
$order_data['tax_lines'][] = $tax_line;
}
// add fees
// Add fees.
foreach ( $order->get_fees() as $fee_item_id => $fee_item ) {
$order_data['fee_lines'][] = array(
'id' => $fee_item_id,
'title' => $fee_item['name'],
@ -290,14 +311,23 @@ class WC_API_Orders extends WC_API_Resource {
);
}
// add coupons
// Add coupons.
foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) {
$order_data['coupon_lines'][] = array(
$coupon_line = array(
'id' => $coupon_item_id,
'code' => $coupon_item['name'],
'amount' => wc_format_decimal( $coupon_item['discount_amount'], $dp ),
);
if ( in_array( 'coupons', $expand ) ) {
$_coupon_data = WC()->api->WC_API_Coupons->get_coupon_by_code( $coupon_item['name'] );
if ( isset( $_coupon_data['coupon'] ) ) {
$coupon_line['coupon_data'] = $_coupon_data['coupon'];
}
}
$order_data['coupon_lines'][] = $coupon_line;
}
return array( 'order' => apply_filters( 'woocommerce_api_order_response', $order_data, $order, $fields, $this->server ) );
@ -516,7 +546,6 @@ class WC_API_Orders extends WC_API_Resource {
* @return array
*/
public function edit_order( $id, $data ) {
try {
if ( ! isset( $data['order'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_missing_order_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'order' ), 400 );
@ -541,21 +570,14 @@ class WC_API_Orders extends WC_API_Resource {
$order_args = array( 'order_id' => $order->id );
// customer note
// Customer note.
if ( isset( $data['note'] ) ) {
$order_args['customer_note'] = $data['note'];
}
// order status
if ( ! empty( $data['status'] ) ) {
$order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '' );
}
// customer ID
// Customer ID.
if ( isset( $data['customer_id'] ) && $data['customer_id'] != $order->get_user_id() ) {
// make sure customer exists
// Make sure customer exists.
if ( false === get_user_by( 'id', $data['customer_id'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ), 400 );
}
@ -563,7 +585,7 @@ class WC_API_Orders extends WC_API_Resource {
update_post_meta( $order->id, '_customer_user', $data['customer_id'] );
}
// billing/shipping address
// Billing/shipping address.
$this->set_order_addresses( $order, $data );
$lines = array(
@ -581,52 +603,46 @@ class WC_API_Orders extends WC_API_Resource {
foreach ( $data[ $line ] as $item ) {
// item ID is always required
// Item ID is always required.
if ( ! array_key_exists( 'id', $item ) ) {
throw new WC_API_Exception( 'woocommerce_invalid_item_id', __( 'Order item ID is required', 'woocommerce' ), 400 );
}
// create item
// Create item.
if ( is_null( $item['id'] ) ) {
$this->set_item( $order, $line_type, $item, 'create' );
} elseif ( $this->item_is_null( $item ) ) {
// delete item
// Delete item.
wc_delete_order_item( $item['id'] );
} else {
// update item
// Update item.
$this->set_item( $order, $line_type, $item, 'update' );
}
}
}
}
// payment method (and payment_complete() if `paid` == true and order needs payment)
// Payment method (and payment_complete() if `paid` == true and order needs payment).
if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) {
// method ID
// Method ID.
if ( isset( $data['payment_details']['method_id'] ) ) {
update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] );
}
// method title
// Method title.
if ( isset( $data['payment_details']['method_title'] ) ) {
update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] );
}
// mark as paid if set
// Mark as paid if set.
if ( $order->needs_payment() && isset( $data['payment_details']['paid'] ) && true === $data['payment_details']['paid'] ) {
$order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' );
}
}
// set order currency
// Set order currency.
if ( isset( $data['currency'] ) ) {
if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) {
throw new WC_API_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce' ), 400 );
}
@ -634,27 +650,30 @@ class WC_API_Orders extends WC_API_Resource {
update_post_meta( $order->id, '_order_currency', $data['currency'] );
}
// if items have changed, recalculate order totals
// If items have changed, recalculate order totals.
if ( $update_totals ) {
$order->calculate_totals();
}
// update order meta
// Update order meta.
if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) {
$this->set_order_meta( $order->id, $data['order_meta'] );
}
// update the order post to set customer note/modified date
// Update the order post to set customer note/modified date.
wc_update_order( $order_args );
// Order status.
if ( ! empty( $data['status'] ) ) {
$order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '' );
}
wc_delete_shop_order_transients( $order->id );
do_action( 'woocommerce_api_edit_order', $order->id, $data, $this );
return $this->get_order( $id );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}

View File

@ -106,13 +106,26 @@ class WC_API_Products extends WC_API_Resource {
array( array( $this, 'create_product_attribute' ), WC_API_SERVER::CREATABLE | WC_API_Server::ACCEPT_DATA ),
);
# GET/PUT/DELETE /attributes/<id>
# GET/PUT/DELETE /products/attributes/<id>
$routes[ $this->base . '/attributes/(?P<id>\d+)' ] = array(
array( array( $this, 'get_product_attribute' ), WC_API_Server::READABLE ),
array( array( $this, 'edit_product_attribute' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
array( array( $this, 'delete_product_attribute' ), WC_API_Server::DELETABLE ),
);
# GET/POST /products/attributes/<attribute_id>/terms
$routes[ $this->base . '/attributes/(?P<attribute_id>\d+)/terms' ] = array(
array( array( $this, 'get_product_attribute_terms' ), WC_API_Server::READABLE ),
array( array( $this, 'create_product_attribute_term' ), WC_API_SERVER::CREATABLE | WC_API_Server::ACCEPT_DATA ),
);
# GET/PUT/DELETE /products/attributes/<attribute_id>/terms/<id>
$routes[ $this->base . '/attributes/(?P<attribute_id>\d+)/terms/(?P<id>\d+)' ] = array(
array( array( $this, 'get_product_attribute_term' ), WC_API_Server::READABLE ),
array( array( $this, 'edit_product_attribute_term' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
array( array( $this, 'delete_product_attribute_term' ), WC_API_Server::DELETABLE ),
);
# POST|PUT /products/bulk
$routes[ $this->base . '/bulk' ] = array(
array( array( $this, 'bulk' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
@ -421,11 +434,11 @@ class WC_API_Products extends WC_API_Resource {
}
/**
* Delete a product
* Delete a product.
*
* @since 2.2
* @param int $id the product ID
* @param bool $force true to permanently delete order, false to move to trash
* @param int $id the product ID.
* @param bool $force true to permanently delete order, false to move to trash.
* @return array
*/
public function delete_product( $id, $force = false ) {
@ -438,7 +451,25 @@ class WC_API_Products extends WC_API_Resource {
do_action( 'woocommerce_api_delete_product', $id, $this );
return $this->delete( $id, 'product', ( 'true' === $force ) );
$parent_id = wp_get_post_parent_id( $id );
$result = ( $force ) ? wp_delete_post( $id, true ) : wp_trash_post( $id );
if ( ! $result ) {
return new WP_Error( 'woocommerce_api_cannot_delete_product', sprintf( __( 'This %s cannot be deleted', 'woocommerce' ), 'product' ), array( 'status' => 500 ) );
}
// Delete parent product transients.
if ( $parent_id ) {
wc_delete_product_transients( $parent_id );
}
if ( $force ) {
return array( 'message' => sprintf( __( 'Permanently deleted %s', 'woocommerce' ), 'product' ) );
} else {
$this->server->send_status( '202' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product' ) );
}
}
/**
@ -1218,10 +1249,11 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save product meta
*
* @since 2.2
* @param int $product_id
* @param array $data
* @since 2.2
* @param int $product_id
* @param array $data
* @return bool
* @throws WC_API_Exception
*/
protected function save_product_meta( $product_id, $data ) {
global $wpdb;
@ -1684,10 +1716,11 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save variations
*
* @since 2.2
* @param int $id
* @param array $data
* @since 2.2
* @param int $id
* @param array $data
* @return bool
* @throws WC_API_Exception
*/
protected function save_variations( $id, $data ) {
global $wpdb;
@ -1805,17 +1838,17 @@ class WC_API_Products extends WC_API_Resource {
}
if ( 'yes' === $managing_stock ) {
$backorders = get_post_meta( $variation_id, '_backorders', true );
if ( isset( $variation['backorders'] ) ) {
if ( 'notify' == $variation['backorders'] ) {
$backorders = 'notify';
} else {
$backorders = ( true === $variation['backorders'] ) ? 'yes' : 'no';
}
} else {
$backorders = 'no';
}
update_post_meta( $variation_id, '_backorders', $backorders );
update_post_meta( $variation_id, '_backorders', '' === $backorders ? 'no' : $backorders );
if ( isset( $variation['stock_quantity'] ) ) {
wc_update_product_stock( $variation_id, wc_stock_amount( $variation['stock_quantity'] ) );
@ -1916,6 +1949,11 @@ class WC_API_Products extends WC_API_Resource {
update_post_meta( $variation_id, '_downloadable_files', '' );
}
// Description.
if ( isset( $variation['description'] ) ) {
update_post_meta( $variation_id, '_variation_description', wp_kses_post( $variation['description'] ) );
}
// Update taxonomies
if ( isset( $variation['attributes'] ) ) {
$updated_attribute_keys = array();
@ -2209,9 +2247,10 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save product images
*
* @since 2.2
* @param array $images
* @param int $id
* @since 2.2
* @param array $images
* @param int $id
* @throws WC_API_Exception
*/
protected function save_product_images( $id, $images ) {
if ( is_array( $images ) ) {
@ -2497,13 +2536,13 @@ class WC_API_Products extends WC_API_Resource {
/**
* Get a listing of product attributes
*
* @since 2.4.0
* @since 2.5.0
* @param string|null $fields fields to limit response to
* @return array
*/
public function get_product_attributes( $fields = null ) {
try {
// Permissions check
// Permissions check.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_attributes', __( 'You do not have permission to read product attributes', 'woocommerce' ), 401 );
}
@ -2531,7 +2570,7 @@ class WC_API_Products extends WC_API_Resource {
/**
* Get the product attribute for the given ID
*
* @since 2.4.0
* @since 2.5.0
* @param string $id product attribute term ID
* @param string|null $fields fields to limit response to
* @return array
@ -2549,7 +2588,7 @@ class WC_API_Products extends WC_API_Resource {
// Permissions check
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_categories', __( 'You do not have permission to read product attributes', 'woocommerce' ), 401 );
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_attributes', __( 'You do not have permission to read product attributes', 'woocommerce' ), 401 );
}
$attribute = $wpdb->get_row( $wpdb->prepare( "
@ -2580,13 +2619,14 @@ class WC_API_Products extends WC_API_Resource {
/**
* Validate attribute data.
*
* @since 2.4.0
* @since 2.5.0
* @param string $name
* @param string $slug
* @param string $type
* @param string $order_by
* @param bool $new_data
* @return bool
* @throws WC_API_Exception
*/
protected function validate_attribute_data( $name, $slug, $type, $order_by, $new_data = true ) {
if ( empty( $name ) ) {
@ -2615,10 +2655,10 @@ class WC_API_Products extends WC_API_Resource {
}
/**
* Create a new product attribute
* Create a new product attribute.
*
* @since 2.4.0
* @param array $data posted data
* @since 2.5.0
* @param array $data Posted data.
* @return array
*/
public function create_product_attribute( $data ) {
@ -2631,7 +2671,7 @@ class WC_API_Products extends WC_API_Resource {
$data = $data['product_attribute'];
// Check permissions
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_product_attribute', __( 'You do not have permission to create product attributes', 'woocommerce' ), 401 );
}
@ -2642,24 +2682,24 @@ class WC_API_Products extends WC_API_Resource {
$data['name'] = '';
}
// Set the attribute slug
// Set the attribute slug.
if ( ! isset( $data['slug'] ) ) {
$data['slug'] = wc_sanitize_taxonomy_name( stripslashes( $data['name'] ) );
} else {
$data['slug'] = preg_replace( '/^pa\_/', '', wc_sanitize_taxonomy_name( stripslashes( $data['slug'] ) ) );
}
// Set attribute type when not sent
// Set attribute type when not sent.
if ( ! isset( $data['type'] ) ) {
$data['type'] = 'select';
}
// Set order by when not sent
// Set order by when not sent.
if ( ! isset( $data['order_by'] ) ) {
$data['order_by'] = 'menu_order';
}
// Validate the attribute data
// Validate the attribute data.
$this->validate_attribute_data( $data['name'], $data['slug'], $data['type'], $data['order_by'], true );
$insert = $wpdb->insert(
@ -2674,7 +2714,7 @@ class WC_API_Products extends WC_API_Resource {
array( '%s', '%s', '%s', '%s', '%d' )
);
// Checks for an error in the product creation
// Checks for an error in the product creation.
if ( is_wp_error( $insert ) ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_create_product_attribute', $insert->get_error_message(), 400 );
}
@ -2683,7 +2723,8 @@ class WC_API_Products extends WC_API_Resource {
do_action( 'woocommerce_api_create_product_attribute', $id, $data );
// Clear transients
// Clear transients.
flush_rewrite_rules();
delete_transient( 'wc_attribute_taxonomies' );
$this->server->send_status( 201 );
@ -2695,10 +2736,10 @@ class WC_API_Products extends WC_API_Resource {
}
/**
* Edit a product attribute
* Edit a product attribute.
*
* @since 2.4.0
* @param int $id the attribute ID
* @since 2.5.0
* @param int $id the attribute ID.
* @param array $data
* @return array
*/
@ -2713,7 +2754,7 @@ class WC_API_Products extends WC_API_Resource {
$id = absint( $id );
$data = $data['product_attribute'];
// Check permissions
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_product_attribute', __( 'You do not have permission to edit product attributes', 'woocommerce' ), 401 );
}
@ -2742,7 +2783,7 @@ class WC_API_Products extends WC_API_Resource {
$attribute_public = $attribute['product_attribute']['has_archives'];
}
// Validate the attribute data
// Validate the attribute data.
$this->validate_attribute_data( $attribute_name, $attribute_slug, $attribute_type, $attribute_order_by, false );
$update = $wpdb->update(
@ -2759,14 +2800,15 @@ class WC_API_Products extends WC_API_Resource {
array( '%d' )
);
// Checks for an error in the product creation
// Checks for an error in the product creation.
if ( false === $update ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_edit_product_attribute', __( 'Could not edit the attribute', 'woocommerce' ), 400 );
}
do_action( 'woocommerce_api_edit_product_attribute', $id, $data );
// Clear transients
// Clear transients.
flush_rewrite_rules();
delete_transient( 'wc_attribute_taxonomies' );
return $this->get_product_attribute( $id );
@ -2776,17 +2818,17 @@ class WC_API_Products extends WC_API_Resource {
}
/**
* Delete a product attribute
* Delete a product attribute.
*
* @since 2.4.0
* @param int $id the product attribute ID
* @since 2.5.0
* @param int $id the product attribute ID.
* @return array
*/
public function delete_product_attribute( $id ) {
global $wpdb;
try {
// Check permissions
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_product_attribute', __( 'You do not have permission to delete product attributes', 'woocommerce' ), 401 );
}
@ -2825,7 +2867,8 @@ class WC_API_Products extends WC_API_Resource {
do_action( 'woocommerce_attribute_deleted', $id, $attribute_name, $taxonomy );
do_action( 'woocommerce_api_delete_product_attribute', $id, $this );
// Clear transients
// Clear transients.
flush_rewrite_rules();
delete_transient( 'wc_attribute_taxonomies' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) );
@ -2834,6 +2877,274 @@ class WC_API_Products extends WC_API_Resource {
}
}
/**
* Get a listing of product attribute terms.
*
* @since 2.5.0
* @param int $attribute_id Attribute ID.
* @param string|null $fields Fields to limit response to.
* @return array
*/
public function get_product_attribute_terms( $attribute_id, $fields = null ) {
try {
// Permissions check.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_attribute_terms', __( 'You do not have permission to read product attribute terms', 'woocommerce' ), 401 );
}
$taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( ! $taxonomy ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_id', __( 'A product attribute with the provided ID could not be found', 'woocommerce' ), 404 );
}
$args = array( 'hide_empty' => false );
$orderby = wc_attribute_orderby( $taxonomy );
switch ( $orderby ) {
case 'name' :
$args['orderby'] = 'name';
$args['menu_order'] = false;
break;
case 'id' :
$args['orderby'] = 'id';
$args['order'] = 'ASC';
$args['menu_order'] = false;
break;
case 'menu_order' :
$args['menu_order'] = 'ASC';
break;
}
$terms = get_terms( $taxonomy, $args );
$attribute_terms = array();
foreach ( $terms as $term ) {
$attribute_terms[] = array(
'id' => $term->term_id,
'slug' => $term->slug,
'name' => $term->name,
'count' => $term->count,
);
}
return array( 'product_attribute_terms' => apply_filters( 'woocommerce_api_product_attribute_terms_response', $attribute_terms, $terms, $fields, $this ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Get the product attribute term for the given ID.
*
* @since 2.5.0
* @param int $attribute_id Attribute ID.
* @param string $id Product attribute term ID.
* @param string|null $fields Fields to limit response to.
* @return array
*/
public function get_product_attribute_term( $attribute_id, $id, $fields = null ) {
global $wpdb;
try {
$id = absint( $id );
// Validate ID
if ( empty( $id ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_term_id', __( 'Invalid product attribute ID', 'woocommerce' ), 400 );
}
// Permissions check
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_attribute_terms', __( 'You do not have permission to read product attribute terms', 'woocommerce' ), 401 );
}
$taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( ! $taxonomy ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_id', __( 'A product attribute with the provided ID could not be found', 'woocommerce' ), 404 );
}
$term = get_term( $id, $taxonomy );
if ( is_wp_error( $term ) || is_null( $term ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_term_id', __( 'A product attribute term with the provided ID could not be found', 'woocommerce' ), 404 );
}
$attribute_term = array(
'id' => $term->term_id,
'slug' => $term->slug,
'name' => $term->name,
'count' => $term->count,
);
return array( 'product_attribute_term' => apply_filters( 'woocommerce_api_product_attribute_response', $attribute_term, $id, $fields, $term, $this ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Create a new product attribute term.
*
* @since 2.5.0
* @param int $attribute_id Attribute ID.
* @param array $data Posted data.
* @return array
*/
public function create_product_attribute_term( $attribute_id, $data ) {
global $wpdb;
try {
if ( ! isset( $data['product_attribute_term'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_missing_product_attribute_term_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'product_attribute_term' ), 400 );
}
$data = $data['product_attribute_term'];
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_product_attribute', __( 'You do not have permission to create product attributes', 'woocommerce' ), 401 );
}
$taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( ! $taxonomy ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_id', __( 'A product attribute with the provided ID could not be found', 'woocommerce' ), 404 );
}
$data = apply_filters( 'woocommerce_api_create_product_attribute_term_data', $data, $this );
// Check if attribute term name is specified.
if ( ! isset( $data['name'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_missing_product_attribute_term_name', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'name' ), 400 );
}
$args = array();
// Set the attribute term slug.
if ( isset( $data['slug'] ) ) {
$args['slug'] = sanitize_title( wp_unslash( $data['slug'] ) );
}
$term = wp_insert_term( $data['name'], $taxonomy, $args );
// Checks for an error in the term creation.
if ( is_wp_error( $term ) ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_create_product_attribute', $term->get_error_message(), 400 );
}
$id = $term['term_id'];
do_action( 'woocommerce_api_create_product_attribute_term', $id, $data );
$this->server->send_status( 201 );
return $this->get_product_attribute_term( $attribute_id, $id );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Edit a product attribute term.
*
* @since 2.5.0
* @param int $attribute_id Attribute ID.
* @param int $id the attribute ID.
* @param array $data
* @return array
*/
public function edit_product_attribute_term( $attribute_id, $id, $data ) {
global $wpdb;
try {
if ( ! isset( $data['product_attribute_term'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_missing_product_attribute_term_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'product_attribute_term' ), 400 );
}
$id = absint( $id );
$data = $data['product_attribute_term'];
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_product_attribute', __( 'You do not have permission to edit product attributes', 'woocommerce' ), 401 );
}
$taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( ! $taxonomy ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_id', __( 'A product attribute with the provided ID could not be found', 'woocommerce' ), 404 );
}
$data = apply_filters( 'woocommerce_api_edit_product_attribute_term_data', $data, $this );
$args = array();
// Update name.
if ( isset( $data['name'] ) ) {
$args['name'] = wc_clean( wp_unslash( $data['name'] ) );
}
// Update slug.
if ( isset( $data['slug'] ) ) {
$args['slug'] = sanitize_title( wp_unslash( $data['slug'] ) );
}
$term = wp_update_term( $id, $taxonomy, $args );
if ( is_wp_error( $term ) ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_edit_product_attribute_term', $term->get_error_message(), 400 );
}
do_action( 'woocommerce_api_edit_product_attribute_term', $id, $data );
return $this->get_product_attribute_term( $attribute_id, $id );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Delete a product attribute term.
*
* @since 2.5.0
* @param int $attribute_id Attribute ID.
* @param int $id the product attribute ID.
* @return array
*/
public function delete_product_attribute_term( $attribute_id, $id ) {
global $wpdb;
try {
// Check permissions.
if ( ! current_user_can( 'manage_product_terms' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_product_attribute_term', __( 'You do not have permission to delete product attribute terms', 'woocommerce' ), 401 );
}
$taxonomy = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( ! $taxonomy ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_attribute_id', __( 'A product attribute with the provided ID could not be found', 'woocommerce' ), 404 );
}
$id = absint( $id );
$term = wp_delete_term( $id, $taxonomy );
if ( ! $term ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_delete_product_attribute_term', sprintf( __( 'This %s cannot be deleted', 'woocommerce' ), 'product_attribute_term' ), 500 );
} else if ( is_wp_error( $term ) ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_delete_product_attribute_term', $term->get_error_message(), 400 );
}
do_action( 'woocommerce_api_delete_product_attribute_term', $id, $this );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Clear product
*/

View File

@ -343,32 +343,35 @@ class WC_API_Webhooks extends WC_API_Resource {
* Helper method to get webhook post objects
*
* @since 2.2
* @param array $args request arguments for filtering query
* @param array $args request arguments for filtering query.
* @return WP_Query
*/
private function query_webhooks( $args ) {
// Set base query arguments
// Set base query arguments.
$query_args = array(
'fields' => 'ids',
'post_type' => 'shop_webhook',
);
// Add status argument
// Add status argument.
if ( ! empty( $args['status'] ) ) {
switch ( $args['status'] ) {
case 'active':
case 'active' :
$query_args['post_status'] = 'publish';
break;
case 'paused':
case 'paused' :
$query_args['post_status'] = 'draft';
break;
case 'disabled':
case 'disabled' :
$query_args['post_status'] = 'pending';
break;
default:
case 'all' :
$query_args['post_status'] = 'any';
break;
default :
$query_args['post_status'] = 'publish';
break;
}
unset( $args['status'] );
}

View File

@ -189,9 +189,10 @@ class WC_API_Authentication {
/**
* Get user by ID
*
* @since 2.4.0
* @param int $user_id
* @since 2.4.0
* @param int $user_id
* @return WC_User
* @throws Exception
*/
private function get_user_by_id( $user_id ) {
$user = get_user_by( 'id', $user_id );

View File

@ -189,9 +189,10 @@ class WC_API_Authentication {
/**
* Get user by ID
*
* @since 2.4.0
* @param int $user_id
* @since 2.4.0
* @param int $user_id
* @return WC_User
* @throws Exception
*/
private function get_user_by_id( $user_id ) {
$user = get_user_by( 'id', $user_id );
@ -327,7 +328,7 @@ class WC_API_Authentication {
$valid_window = 15 * 60; // 15 minute window
if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) {
throw new Exception( __( 'Invalid timestamp', 'woocommerce' ) );
throw new Exception( __( 'Invalid timestamp', 'woocommerce' ), 401 );
}
$used_nonces = maybe_unserialize( $keys['nonces'] );

View File

@ -516,7 +516,6 @@ class WC_API_Orders extends WC_API_Resource {
* @return array
*/
public function edit_order( $id, $data ) {
try {
if ( ! isset( $data['order'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_missing_order_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'order' ), 400 );
@ -541,21 +540,14 @@ class WC_API_Orders extends WC_API_Resource {
$order_args = array( 'order_id' => $order->id );
// customer note
// Customer note.
if ( isset( $data['note'] ) ) {
$order_args['customer_note'] = $data['note'];
}
// order status
if ( ! empty( $data['status'] ) ) {
$order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '' );
}
// customer ID
// Customer ID.
if ( isset( $data['customer_id'] ) && $data['customer_id'] != $order->get_user_id() ) {
// make sure customer exists
// Make sure customer exists.
if ( false === get_user_by( 'id', $data['customer_id'] ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ), 400 );
}
@ -563,7 +555,7 @@ class WC_API_Orders extends WC_API_Resource {
update_post_meta( $order->id, '_customer_user', $data['customer_id'] );
}
// billing/shipping address
// Billing/shipping address.
$this->set_order_addresses( $order, $data );
$lines = array(
@ -581,52 +573,46 @@ class WC_API_Orders extends WC_API_Resource {
foreach ( $data[ $line ] as $item ) {
// item ID is always required
// Item ID is always required.
if ( ! array_key_exists( 'id', $item ) ) {
throw new WC_API_Exception( 'woocommerce_invalid_item_id', __( 'Order item ID is required', 'woocommerce' ), 400 );
}
// create item
// Create item.
if ( is_null( $item['id'] ) ) {
$this->set_item( $order, $line_type, $item, 'create' );
} elseif ( $this->item_is_null( $item ) ) {
// delete item
// Delete item.
wc_delete_order_item( $item['id'] );
} else {
// update item
// Update item.
$this->set_item( $order, $line_type, $item, 'update' );
}
}
}
}
// payment method (and payment_complete() if `paid` == true and order needs payment)
// Payment method (and payment_complete() if `paid` == true and order needs payment).
if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) {
// method ID
// Method ID.
if ( isset( $data['payment_details']['method_id'] ) ) {
update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] );
}
// method title
// Method title.
if ( isset( $data['payment_details']['method_title'] ) ) {
update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] );
}
// mark as paid if set
// Mark as paid if set.
if ( $order->needs_payment() && isset( $data['payment_details']['paid'] ) && true === $data['payment_details']['paid'] ) {
$order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' );
}
}
// set order currency
// Set order currency.
if ( isset( $data['currency'] ) ) {
if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) {
throw new WC_API_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce' ), 400 );
}
@ -634,19 +620,24 @@ class WC_API_Orders extends WC_API_Resource {
update_post_meta( $order->id, '_order_currency', $data['currency'] );
}
// if items have changed, recalculate order totals
// If items have changed, recalculate order totals.
if ( $update_totals ) {
$order->calculate_totals();
}
// update order meta
// Update order meta.
if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) {
$this->set_order_meta( $order->id, $data['order_meta'] );
}
// update the order post to set customer note/modified date
// Update the order post to set customer note/modified date.
wc_update_order( $order_args );
// Order status.
if ( ! empty( $data['status'] ) ) {
$order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '' );
}
wc_delete_shop_order_transients( $order->id );
do_action( 'woocommerce_api_edit_order', $order->id, $data, $this );

View File

@ -389,11 +389,11 @@ class WC_API_Products extends WC_API_Resource {
}
/**
* Delete a product
* Delete a product.
*
* @since 2.2
* @param int $id the product ID
* @param bool $force true to permanently delete order, false to move to trash
* @param int $id the product ID.
* @param bool $force true to permanently delete order, false to move to trash.
* @return array
*/
public function delete_product( $id, $force = false ) {
@ -406,7 +406,25 @@ class WC_API_Products extends WC_API_Resource {
do_action( 'woocommerce_api_delete_product', $id, $this );
return $this->delete( $id, 'product', ( 'true' === $force ) );
$parent_id = wp_get_post_parent_id( $id );
$result = ( $force ) ? wp_delete_post( $id, true ) : wp_trash_post( $id );
if ( ! $result ) {
return new WP_Error( 'woocommerce_api_cannot_delete_product', sprintf( __( 'This %s cannot be deleted', 'woocommerce' ), 'product' ), array( 'status' => 500 ) );
}
// Delete parent product transients.
if ( $parent_id ) {
wc_delete_product_transients( $parent_id );
}
if ( $force ) {
return array( 'message' => sprintf( __( 'Permanently deleted %s', 'woocommerce' ), 'product' ) );
} else {
$this->server->send_status( '202' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product' ) );
}
}
/**
@ -765,10 +783,11 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save product meta
*
* @since 2.2
* @param int $product_id
* @param array $data
* @since 2.2
* @param int $product_id
* @param array $data
* @return bool
* @throws WC_API_Exception
*/
protected function save_product_meta( $product_id, $data ) {
global $wpdb;
@ -1226,10 +1245,11 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save variations
*
* @since 2.2
* @param int $id
* @param array $data
* @since 2.2
* @param int $id
* @param array $data
* @return bool
* @throws WC_API_Exception
*/
protected function save_variations( $id, $data ) {
global $wpdb;
@ -1347,17 +1367,17 @@ class WC_API_Products extends WC_API_Resource {
}
if ( 'yes' === $managing_stock ) {
$backorders = get_post_meta( $variation_id, '_backorders', true );
if ( isset( $variation['backorders'] ) ) {
if ( 'notify' == $variation['backorders'] ) {
$backorders = 'notify';
} else {
$backorders = ( true === $variation['backorders'] ) ? 'yes' : 'no';
}
} else {
$backorders = 'no';
}
update_post_meta( $variation_id, '_backorders', $backorders );
update_post_meta( $variation_id, '_backorders', '' === $backorders ? 'no' : $backorders );
if ( isset( $variation['stock_quantity'] ) ) {
wc_update_product_stock( $variation_id, wc_stock_amount( $variation['stock_quantity'] ) );
@ -1746,9 +1766,10 @@ class WC_API_Products extends WC_API_Resource {
/**
* Save product images
*
* @since 2.2
* @param array $images
* @param int $id
* @since 2.2
* @param array $images
* @param int $id
* @throws WC_API_Exception
*/
protected function save_product_images( $id, $images ) {
if ( is_array( $images ) ) {
@ -1798,9 +1819,10 @@ class WC_API_Products extends WC_API_Resource {
/**
* Upload image from URL
*
* @since 2.2
* @param string $image_url
* @since 2.2
* @param string $image_url
* @return int|WP_Error attachment id
* @throws WC_API_Exception
*/
public function upload_product_image( $image_url ) {
$file_name = basename( current( explode( '?', $image_url ) ) );
@ -2064,6 +2086,7 @@ class WC_API_Products extends WC_API_Resource {
* @param string $order_by
* @param bool $new_data
* @return bool
* @throws WC_API_Exception
*/
protected function validate_attribute_data( $name, $slug, $type, $order_by, $new_data = true ) {
if ( empty( $name ) ) {

View File

@ -362,25 +362,25 @@ class WC_API_Resource {
$result = wp_delete_user( $id );
if ( $result )
if ( $result ) {
return array( 'message' => __( 'Permanently deleted customer', 'woocommerce' ) );
else
} else {
return new WP_Error( 'woocommerce_api_cannot_delete_customer', __( 'The customer cannot be deleted', 'woocommerce' ), array( 'status' => 500 ) );
}
} else {
// delete order/coupon/product/webhook
// delete order/coupon/webhook
$result = ( $force ) ? wp_delete_post( $id, true ) : wp_trash_post( $id );
if ( ! $result )
if ( ! $result ) {
return new WP_Error( "woocommerce_api_cannot_delete_{$resource_name}", sprintf( __( 'This %s cannot be deleted', 'woocommerce' ), $resource_name ), array( 'status' => 500 ) );
}
if ( $force ) {
return array( 'message' => sprintf( __( 'Permanently deleted %s', 'woocommerce' ), $resource_name ) );
} else {
$this->server->send_status( '202' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), $resource_name ) );

View File

@ -21,8 +21,8 @@ class WC_AJAX {
* Hook in ajax handlers.
*/
public static function init() {
add_action( 'init', array( __CLASS__, 'define_ajax'), 0 );
add_action( 'template_redirect', array( __CLASS__, 'do_wc_ajax'), 0 );
add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 );
add_action( 'template_redirect', array( __CLASS__, 'do_wc_ajax' ), 0 );
self::add_ajax_events();
}
@ -51,15 +51,22 @@ class WC_AJAX {
@ini_set( 'display_errors', 0 );
}
$GLOBALS['wpdb']->hide_errors();
// Send headers like admin-ajax.php
send_origin_headers();
@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
@header( 'X-Robots-Tag: noindex' );
send_nosniff_header();
nocache_headers();
}
}
/**
* Send headers for WC Ajax Requests
* @since 2.5.0
*/
private static function wc_ajax_headers() {
send_origin_headers();
@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
@header( 'X-Robots-Tag: noindex' );
send_nosniff_header();
nocache_headers();
status_header( 200 );
}
/**
* Check for WC Ajax request and fire action.
*/
@ -71,6 +78,7 @@ class WC_AJAX {
}
if ( $action = $wp_query->get( 'wc-ajax' ) ) {
self::wc_ajax_headers();
do_action( 'wc_ajax_' . sanitize_text_field( $action ) );
die();
}

View File

@ -235,6 +235,7 @@ class WC_Auth {
* @param string $url
*
* @return bool
* @throws Exception
*/
protected function post_consumer_data( $consumer_data, $url ) {
$params = array(

View File

@ -17,7 +17,7 @@ class WC_Autoloader {
/**
* Path to the includes directory.
*
*
* @var string
*/
private $include_path = '';
@ -37,7 +37,7 @@ class WC_Autoloader {
/**
* Take a class name and turn it into a file name.
*
*
* @param string $class
* @return string
*/
@ -47,7 +47,7 @@ class WC_Autoloader {
/**
* Include a class file.
*
*
* @param string $path
* @return bool successful or not
*/

View File

@ -278,7 +278,7 @@ class WC_Breadcrumb {
}
/**
* Add crumbs for date based archives.
* Add crumbs for taxonomies
*/
private function add_crumbs_tax() {
$this_term = $GLOBALS['wp_query']->get_queried_object();
@ -287,8 +287,7 @@ class WC_Breadcrumb {
$this->add_crumb( $taxonomy->labels->name );
if ( 0 != $this_term->parent ) {
$this->term_ancestors( $this_term->parent, 'post_category' );
$this->add_crumb( $this_term->name, get_term_link( $this_term->term_id, $this_term->taxonomy ) );
$this->term_ancestors( $this_term->term_id, $this_term->taxonomy );
}
$this->add_crumb( single_term_title( '', false ), get_term_link( $this_term->term_id, $this_term->taxonomy ) );

View File

@ -25,6 +25,31 @@ class WC_Cache_Helper {
add_action( 'delete_version_transients', array( __CLASS__, 'delete_version_transients' ) );
}
/**
* Get prefix for use with wp_cache_set. Allows all cache in a group to be invalidated at once.
* @param string $group
* @return string
*/
public static function get_cache_prefix( $group ) {
// Get cache key - uses cache key wc_orders_cache_prefix to invalidate when needed
$prefix = wp_cache_get( 'wc_' . $group . '_cache_prefix', $group );
if ( false === $prefix ) {
$prefix = 1;
wp_cache_set( 'wc_' . $group . '_cache_prefix', $prefix, $group );
}
return 'wc_cache_' . $prefix . '_';
}
/**
* Increment group cache prefix (invalidates cache).
* @param string $group
*/
public static function incr_cache_prefix( $group ) {
wp_cache_incr( 'wc_' . $group . '_cache_prefix', 1, $group );
}
/**
* Get a hash of the customer location.
* @return string

View File

@ -42,12 +42,6 @@ class WC_Cart {
/** @var float The total cost of the cart items. */
public $cart_contents_total;
/** @var float The total weight of the cart items. */
public $cart_contents_weight;
/** @var float The total count of the cart items. */
public $cart_contents_count;
/** @var float Cart grand total. */
public $total;
@ -84,8 +78,6 @@ class WC_Cart {
/** @var array cart_session_data. Array of data the cart calculates and stores in the session with defaults */
public $cart_session_data = array(
'cart_contents_total' => 0,
'cart_contents_weight' => 0,
'cart_contents_count' => 0,
'total' => 0,
'subtotal' => 0,
'subtotal_ex_tax' => 0,
@ -149,7 +141,13 @@ class WC_Cart {
*/
public function __get( $key ) {
switch ( $key ) {
case 'tax':
case 'cart_contents_weight' :
return $this->get_cart_contents_weight();
break;
case 'cart_contents_count' :
return $this->get_cart_contents_count();
break;
case 'tax' :
_deprecated_argument( 'WC_Cart->tax', '2.3', 'Use WC_Tax:: directly' );
$this->tax = new WC_Tax();
return $this->tax;
@ -345,11 +343,25 @@ class WC_Cart {
/**
* Get number of items in the cart.
*
* @return int
*/
public function get_cart_contents_count() {
return apply_filters( 'woocommerce_cart_contents_count', $this->cart_contents_count );
return apply_filters( 'woocommerce_cart_contents_count', array_sum( wp_list_pluck( $this->get_cart(), 'quantity' ) ) );
}
/**
* Get weight of items in the cart.
* @since 2.5.0
* @return int
*/
public function get_cart_contents_weight() {
$weight = 0;
foreach ( $this->get_cart() as $cart_item_key => $values ) {
$weight += $values['data']->get_weight() * $values['quantity'];
}
return apply_filters( 'woocommerce_cart_contents_weight', $weight );
}
/**
@ -1097,17 +1109,9 @@ class WC_Cart {
* Calculate subtotals for items. This is done first so that discount logic can use the values.
*/
foreach ( $cart as $cart_item_key => $values ) {
$_product = $values['data'];
// Count items + weight
$this->cart_contents_weight += $_product->get_weight() * $values['quantity'];
$this->cart_contents_count += $values['quantity'];
// Prices
$line_price = $_product->get_price() * $values['quantity'];
$line_subtotal = 0;
$_product = $values['data'];
$line_price = $_product->get_price() * $values['quantity'];
$line_subtotal = 0;
$line_subtotal_tax = 0;
/**

View File

@ -643,7 +643,7 @@ class WC_Checkout {
$result = $available_gateways[ $this->posted['payment_method'] ]->process_payment( $order_id );
// Redirect to success/confirmation/payment page
if ( $result['result'] == 'success' ) {
if ( 'success' === $result['result'] ) {
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );

View File

@ -226,15 +226,13 @@ class WC_Comments {
}
/**
* Clear transients for a review.
* Ensure product average rating and review count is kept up to date.
* @param int $post_id
*/
public static function clear_transients( $post_id ) {
$post_id = absint( $post_id );
$transient_version = WC_Cache_Helper::get_transient_version( 'product' );
delete_transient( 'wc_average_rating_' . $post_id . $transient_version );
delete_transient( 'wc_rating_count_' . $post_id . $transient_version );
delete_transient( 'wc_review_count_' . $post_id . $transient_version );
delete_post_meta( $post_id, '_wc_average_rating' );
delete_post_meta( $post_id, '_wc_rating_count' );
delete_post_meta( $post_id, '_wc_review_count' );
}
/**

View File

@ -534,8 +534,8 @@ class WC_Countries {
'validate' => array( 'state' )
),
'postcode' => array(
'label' => __( 'Postcode / Zip', 'woocommerce' ),
'placeholder' => __( 'Postcode / Zip', 'woocommerce' ),
'label' => __( 'Postcode / ZIP', 'woocommerce' ),
'placeholder' => __( 'Postcode / ZIP', 'woocommerce' ),
'required' => true,
'class' => array( 'form-row-last', 'address-field' ),
'clear' => true,
@ -865,8 +865,8 @@ class WC_Countries {
),
'US' => array(
'postcode' => array(
'label' => __( 'Zip', 'woocommerce' ),
'placeholder' => __( 'Zip', 'woocommerce' ),
'label' => __( 'ZIP', 'woocommerce' ),
'placeholder' => __( 'ZIP', 'woocommerce' ),
),
'state' => array(
'label' => __( 'State', 'woocommerce' ),
@ -958,10 +958,11 @@ class WC_Countries {
$address_fields = array();
foreach ( $fields as $key => $value ) {
$keys = array_keys( $fields );
$address_fields[ $type . $key ] = $value;
// Add email and phone after company or last
if ( $type == 'billing_' && ( 'company' === $key || ( ! array_key_exists( 'company', $fields ) && $key === end( array_keys( $fields ) ) ) ) ) {
if ( $type == 'billing_' && ( 'company' === $key || ( ! array_key_exists( 'company', $fields ) && $key === end( $keys ) ) ) ) {
$address_fields['billing_email'] = array(
'label' => __( 'Email Address', 'woocommerce' ),
'required' => true,

View File

@ -144,21 +144,22 @@ class WC_Coupon {
/**
* Get a coupon ID from it's code.
* @since 2.5.0 woocommerce_coupon_code_query was removed in favour of woocommerce_get_coupon_id_from_code filter on the return. wp_cache was also implemented.
* @param string $code
* @return int
*/
private function get_coupon_id_from_code( $code ) {
global $wpdb;
$coupon_code_query = $wpdb->prepare( apply_filters( 'woocommerce_coupon_code_query', "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish'" ), $this->code );
$transient_name = 'wc_cid_by_code_' . md5( $coupon_code_query . WC_Cache_Helper::get_transient_version( 'coupons' ) );
$coupon_id = wp_cache_get( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $code, 'coupons' );
if ( false === ( $result = get_transient( $transient_name ) ) ) {
$result = $wpdb->get_var( $coupon_code_query );
set_transient( $transient_name, $result, DAY_IN_SECONDS * 30 );
if ( false === $coupon_id ) {
$sql = $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish'", $this->code );
$coupon_id = apply_filters( 'woocommerce_get_coupon_id_from_code', $wpdb->get_var( $sql ), $this->code );
wp_cache_set( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $code, $coupon_id, 'coupons' );
}
return absint( $result );
return absint( $coupon_id );
}
/**
@ -353,6 +354,7 @@ class WC_Coupon {
* Checked again for emails later on in WC_Cart::check_customer_coupons().
*
* @param int $user_id
* @throws Exception
*/
private function validate_user_usage_limit( $user_id = null ) {
if ( ! $user_id ) {
@ -426,7 +428,8 @@ class WC_Coupon {
$valid_for_cart = false;
if ( ! WC()->cart->is_empty() ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_cats = wp_get_post_terms( $cart_item['product_id'], 'product_cat', array( "fields" => "ids" ) );
$product_cats = wc_get_product_cat_ids( $cart_item['product_id'] );
if ( sizeof( array_intersect( $product_cats, $this->product_categories ) ) > 0 ) {
$valid_for_cart = true;
}
@ -503,7 +506,7 @@ class WC_Coupon {
if ( ! WC()->cart->is_empty() ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_cats = wp_get_post_terms( $cart_item['product_id'], 'product_cat', array( "fields" => "ids" ) );
$product_cats = wc_get_product_cat_ids( $cart_item['product_id'] );
if ( sizeof( array_intersect( $product_cats, $this->exclude_product_categories ) ) > 0 ) {
$valid_for_cart = false;
@ -590,7 +593,7 @@ class WC_Coupon {
}
$valid = false;
$product_cats = wp_get_post_terms( $product->id, 'product_cat', array( "fields" => "ids" ) );
$product_cats = wc_get_product_cat_ids( $product->id );
// Specific products get the discount
if ( sizeof( $this->product_ids ) > 0 ) {
@ -803,8 +806,7 @@ class WC_Coupon {
$categories = array();
if ( ! WC()->cart->is_empty() ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_cats = wp_get_post_terms( $cart_item['product_id'], 'product_cat', array( "fields" => "ids" ) );
$product_cats = wc_get_product_cat_ids( $cart_item['product_id'] );
if ( sizeof( $intersect = array_intersect( $product_cats, $this->exclude_product_categories ) ) > 0 ) {

View File

@ -107,6 +107,7 @@ class WC_Emails {
// Email Header, Footer and content hooks
add_action( 'woocommerce_email_header', array( $this, 'email_header' ) );
add_action( 'woocommerce_email_footer', array( $this, 'email_footer' ) );
add_action( 'woocommerce_email_order_details', array( $this, 'order_details' ), 10, 4 );
add_action( 'woocommerce_email_order_meta', array( $this, 'order_meta' ), 10, 3 );
add_action( 'woocommerce_email_customer_details', array( $this, 'customer_details' ), 10, 3 );
add_action( 'woocommerce_email_customer_details', array( $this, 'email_addresses' ), 20, 3 );
@ -254,6 +255,17 @@ class WC_Emails {
$email->trigger( $customer_id, $user_pass, $password_generated );
}
/**
* Show the order details table
*/
public function order_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
if ( $plain_text ) {
wc_get_template( 'emails/plain/email-order-details.php', array( 'order' => $order, 'sent_to_admin' => $sent_to_admin, 'plain_text' => $plain_text, 'email' => $email ) );
} else {
wc_get_template( 'emails/email-order-details.php', array( 'order' => $order, 'sent_to_admin' => $sent_to_admin, 'plain_text' => $plain_text, 'email' => $email ) );
}
}
/**
* Add order meta to email templates.
*

174
includes/class-wc-embed.php Normal file
View File

@ -0,0 +1,174 @@
<?php
/**
* WooCommerce Product Embed.
*
* @version 2.4.11
* @package WooCommerce/Classes/Embed
* @category Class
* @author WooThemes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Embed Class which handles any WooCommerce Products that are embedded on this site or another site.
*
* @class WC_Embed
* @version 2.4.11
* @author WooThemes
*/
class WC_Embed {
/**
* Init embed class.
*
* @since 2.4.11
*/
public static function init() {
// Filter all of the content that's going to be embedded.
add_filter( 'the_title', array( __CLASS__, 'the_title' ), 10 );
add_filter( 'the_excerpt_embed', array( __CLASS__, 'the_excerpt' ), 10 );
// Make sure no comments display. Doesn't make sense for products.
remove_action( 'embed_content_meta', 'print_embed_comments_button' );
// In the comments place let's display the product rating.
add_action( 'embed_content_meta', array( __CLASS__, 'get_ratings' ), 5 );
// Add some basic styles.
add_action( 'embed_head', array( __CLASS__, 'print_embed_styles' ) );
}
/**
* Create the title for embedded products - we want to add the price to it.
*
* @since 2.4.11
* @param string $title Embed title.
* @return string
*/
public static function the_title( $title ) {
// Make sure we're only affecting embedded products.
if ( self::is_embedded_product() ) {
// Get product.
$_product = wc_get_product( get_the_ID() );
// Add the price.
$title = $title . '<span class="wc-embed-price">' . $_product->get_price_html() . '</span>';
}
return $title;
}
/**
* Check if this is an embedded product - to make sure we don't mess up regular posts.
*
* @since 2.4.11
* @return bool
*/
public static function is_embedded_product() {
if ( function_exists( 'is_embed' ) && is_embed() && is_product() ) {
return true;
}
return false;
}
/**
* Create the excerpt for embedded products - we want to add the buy button to it.
*
* @since 2.4.11
* @param string $excerpt Embed short description.
* @return string
*/
public static function the_excerpt( $excerpt ) {
global $post;
// Make sure we're only affecting embedded products.
if ( self::is_embedded_product() ) {
if ( ! empty( $post->post_excerpt ) ) {
ob_start();
woocommerce_template_single_excerpt();
$excerpt = ob_get_clean();
}
// Add the button.
$excerpt .= self::product_buttons();
}
return $excerpt;
}
/**
* Create the button to go to the product page for embedded products.
*
* @since 2.4.11
* @return string
*/
public static function product_buttons() {
$_product = wc_get_product( get_the_ID() );
$buttons = array();
$button = '<a href="%s" class="wp-embed-more wc-embed-button">%s</a>';
if ( $_product->is_type( 'simple' ) && $_product->is_purchasable() && $_product->is_in_stock() ) {
$buttons[] = sprintf( $button, esc_url( add_query_arg( 'add-to-cart', get_the_ID(), wc_get_cart_url() ) ), esc_html__( 'Buy Now', 'woocommerce' ) );
}
$buttons[] = sprintf( $button, get_the_permalink(), esc_html__( 'Read More', 'woocommerce' ) );
return '<p>' . implode( ' ', $buttons ) . '</p>';
}
/**
* Prints the markup for the rating stars.
*
* @since 2.4.11
*/
public static function get_ratings() {
// Make sure we're only affecting embedded products.
if ( self::is_embedded_product() && ( $_product = wc_get_product( get_the_ID() ) ) && $_product->get_average_rating() > 0 ) {
?>
<div class="wc-embed-rating">
<?php echo esc_html( sprintf( __( 'Rated %s out of 5', 'woocommerce' ), $_product->get_average_rating() ) ); ?>
</div>
<?php
}
}
/**
* Basic styling.
*/
public static function print_embed_styles() {
if ( ! self::is_embedded_product() ) {
return;
}
?>
<style type="text/css">
a.wc-embed-button {
border-radius: 4px;
border: 1px solid #ddd;
box-shadow: 0px 1px 0 0px rgba(0, 0, 0, 0.05);
display:inline-block;
padding: .5em;
}
a.wc-embed-button:hover, a.wc-embed-button:focus {
border: 1px solid #ccc;
box-shadow: 0px 1px 0 0px rgba(0, 0, 0, 0.1);
color: #999;
text-decoration: none;
}
.wp-embed-excerpt p {
margin: 0 0 1em;
}
.wc-embed-price {
float:right;
}
.wc-embed-rating {
display: inline-block;
}
</style>
<?php
}
}
WC_Embed::init();

View File

@ -325,7 +325,7 @@ class WC_Form_Handler {
$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
// Redirect to success/confirmation/payment page
if ( 'success' == $result['result'] ) {
if ( 'success' === $result['result'] ) {
wp_redirect( $result['redirect'] );
exit;
}

View File

@ -311,10 +311,13 @@ class WC_Frontend_Scripts {
);
break;
case 'wc-add-to-cart-variation' :
// We also need the wp.template for this script :)
wc_get_template( 'single-product/add-to-cart/variation.php' );
return array(
'i18n_no_matching_variations_text' => esc_attr__( 'Sorry, no products matched your selection. Please choose a different combination.', 'woocommerce' ),
'i18n_make_a_selection_text' => esc_attr__( 'Select product options before adding this product to your cart.', 'woocommerce' ),
'i18n_unavailable_text' => esc_attr__( 'Sorry, this product is unavailable. Please choose a different combination.', 'woocommerce' ),
'i18n_unavailable_text' => esc_attr__( 'Sorry, this product is unavailable. Please choose a different combination.', 'woocommerce' )
);
break;
case 'wc-country-select' :

View File

@ -58,9 +58,8 @@ class WC_Order extends WC_Abstract_Order {
/**
* Get order refunds.
*
* @since 2.2
* @return array
* @return array of WC_Order_Refund objects
*/
public function get_refunds() {
if ( empty( $this->refunds ) && ! is_array( $this->refunds ) ) {

View File

@ -137,7 +137,6 @@ class WC_Payment_Gateways {
/**
* Get available gateways.
*
* @access public
* @return array
*/
public function get_available_payment_gateways() {
@ -158,14 +157,27 @@ class WC_Payment_Gateways {
/**
* Set the current, active gateway.
*
* @param array $gateway Available payment gateways.
*/
public function set_current_gateway( $gateways ) {
// Be on the defensive
if ( ! is_array( $gateways ) || empty( $gateways ) ) {
return;
}
$current = WC()->session->get( 'chosen_payment_method' );
if ( isset( $gateways[ $current ] ) ) {
$gateways[ $current ]->set_current();
if ( $current && isset( $gateways[ $current ] ) ) {
$current_gateway = $gateways[ $current ];
} else {
current( $gateways )->set_current();
$current_gateway = current( $gateways );
}
// Ensure we can make a call to set_current() without triggering an error
if ( $current_gateway && is_callable( array( $current_gateway, 'set_current' ) ) ) {
$current_gateway->set_current();
}
}

View File

@ -399,7 +399,7 @@ class WC_Post_types {
'parent' => __( 'Parent Webhook', 'woocommerce' )
),
'public' => false,
'show_ui' => false,
'show_ui' => true,
'capability_type' => 'shop_webhook',
'map_meta_cap' => true,
'publicly_queryable' => false,

View File

@ -20,9 +20,6 @@ class WC_Product_Grouped extends WC_Product {
/** @public array Array of child products/posts/variations. */
public $children;
/** @public string The product's total stock, including that of its children. */
public $total_stock;
/**
* __construct function.
*
@ -44,40 +41,6 @@ class WC_Product_Grouped extends WC_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'View products', 'woocommerce' ), $this );
}
/**
* Get total stock.
*
* This is the stock of parent and children combined.
*
* @access public
* @return int
*/
public function get_total_stock() {
if ( empty( $this->total_stock ) ) {
$transient_name = 'wc_product_total_stock_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
if ( false === ( $this->total_stock = get_transient( $transient_name ) ) ) {
$this->total_stock = $this->stock;
if ( sizeof( $this->get_children() ) > 0 ) {
foreach ( $this->get_children() as $child_id ) {
$stock = get_post_meta( $child_id, '_stock', true );
if ( $stock != '' ) {
$this->total_stock += wc_stock_amount( $stock );
}
}
}
set_transient( $transient_name, $this->total_stock, DAY_IN_SECONDS * 30 );
}
}
return wc_stock_amount( $this->total_stock );
}
/**
* Return the products children posts.
*

View File

@ -20,9 +20,6 @@ class WC_Product_Variable extends WC_Product {
/** @public array Array of child products/posts/variations. */
public $children = null;
/** @public string The product's total stock, including that of its children. */
public $total_stock;
/** @private array Array of variation prices. */
private $prices_array = array();
@ -46,35 +43,6 @@ class WC_Product_Variable extends WC_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Select options', 'woocommerce' ), $this );
}
/**
* Get total stock.
*
* This is the stock of parent and children combined.
*
* @access public
* @return int
*/
public function get_total_stock() {
if ( empty( $this->total_stock ) ) {
$transient_name = 'wc_product_total_stock_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' );
if ( false === ( $this->total_stock = get_transient( $transient_name ) ) ) {
$this->total_stock = max( 0, wc_stock_amount( $this->stock ) );
if ( sizeof( $this->get_children() ) > 0 ) {
foreach ( $this->get_children() as $child_id ) {
if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
$stock = get_post_meta( $child_id, '_stock', true );
$this->total_stock += max( 0, wc_stock_amount( $stock ) );
}
}
}
set_transient( $transient_name, $this->total_stock, DAY_IN_SECONDS * 30 );
}
}
return wc_stock_amount( $this->total_stock );
}
/**
* Set stock level of the product.
*
@ -265,12 +233,10 @@ class WC_Product_Variable extends WC_Product {
global $wp_filter;
/**
* Transient name for storing prices for this product.
* Max transient length is 45, -10 for get_transient_version.
* @var string
* Transient name for storing prices for this product (note: Max transient length is 45)
* @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
*/
$transient_name = 'wc_var_prices' . $this->id . '_' . WC_Cache_Helper::get_transient_version( 'product' );
$transient_name = 'wc_var_prices_' . $this->id;
/**
* Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
@ -283,9 +249,11 @@ class WC_Product_Variable extends WC_Product {
$price_hash = array( false );
}
foreach ( $wp_filter as $key => $val ) {
if ( in_array( $key, array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' ) ) ) {
$price_hash[ $key ] = $val;
$filter_names = array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' );
foreach ( $filter_names as $filter_name ) {
if ( ! empty( $wp_filter[ $filter_name ] ) ) {
$price_hash[ $filter_name ] = $wp_filter[ $filter_name ];
}
}
@ -597,8 +565,10 @@ class WC_Product_Variable extends WC_Product {
$image_link = $full_attachment ? current( $full_attachment ) : '';
$image_title = get_the_title( $attachment_id );
$image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $attachment_id, 'shop_single' ) : '';
$image_sizes = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $attachment_id, 'shop_single' ) : '';
} else {
$image = $image_link = $image_title = $image_alt = '';
$image = $image_link = $image_title = $image_alt = $image_srcset = $image_sizes = '';
}
$availability = $variation->get_availability();
@ -617,6 +587,8 @@ class WC_Product_Variable extends WC_Product {
'image_link' => $image_link,
'image_title' => $image_title,
'image_alt' => $image_alt,
'image_srcset' => $image_srcset,
'image_sizes' => $image_sizes,
'price_html' => apply_filters( 'woocommerce_show_variation_price', $variation->get_price() === "" || $this->get_variation_price( 'min' ) !== $this->get_variation_price( 'max' ), $this, $variation ) ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'availability_html' => $availability_html,
'sku' => $variation->get_sku(),
@ -747,12 +719,10 @@ class WC_Product_Variable extends WC_Product {
'post_status' => 'publish'
) );
// No published variations - update parent post status. Use $wpdb to prevent endless loop on save_post hooks.
if ( ! $children && get_post_status( $product_id ) == 'publish' ) {
$wpdb->update( $wpdb->posts, array( 'post_status' => 'draft' ), array( 'ID' => $product_id ) );
// No published variations - product won't be purchasable.
if ( ! $children && 'publish' === get_post_status( $product_id ) ) {
if ( is_admin() ) {
WC_Admin_Meta_Boxes::add_error( __( 'This variable product has no active variations so cannot be published. Changing status to draft.', 'woocommerce' ) );
WC_Admin_Meta_Boxes::add_error( __( 'This variable product has no active variations. Add or enable variations to allow this product to be purchased.', 'woocommerce' ) );
}
// Loop the variations

View File

@ -147,6 +147,17 @@ class WC_Product_Variation extends WC_Product {
return $value;
}
/**
* Return the variation ID
*
* @since 2.5.0
* @return int variation (post) ID
*/
public function get_id() {
return $this->variation_id;
}
/**
* Returns whether or not the product post exists.
*

View File

@ -563,7 +563,7 @@ class WC_Query {
$args['order'] = $order == 'ASC' ? 'ASC' : 'DESC';
break;
case 'price' :
$args['orderby'] = "meta_value_num {$wpdb->posts}.ID";
$args['orderby'] = "meta_value_num ID";
$args['order'] = $order == 'DESC' ? 'DESC' : 'ASC';
$args['meta_key'] = '_price';
break;

View File

@ -163,14 +163,7 @@ class WC_Session_Handler extends WC_Session {
* @return string
*/
private function get_cache_prefix() {
$prefix_num = wp_cache_get( 'wc_session_prefix', WC_SESSION_CACHE_GROUP );
if ( $prefix_num === false ) {
$prefix_num = 1;
wp_cache_set( 'wc_session_prefix', $prefix_num, WC_SESSION_CACHE_GROUP );
}
return 'wc_session_' . $prefix_num . '_';
return WC_Cache_Helper::get_cache_prefix( WC_SESSION_CACHE_GROUP );
}
/**
@ -262,7 +255,7 @@ class WC_Session_Handler extends WC_Session {
$wpdb->query( $wpdb->prepare( "DELETE FROM $this->_table WHERE session_expiry < %d", time() ) );
// Invalidate cache
wp_cache_incr( 'wc_session_prefix', 1, WC_SESSION_CACHE_GROUP );
WC_Cache_Helper::incr_cache_prefix( WC_SESSION_CACHE_GROUP );
}
}

View File

@ -145,7 +145,7 @@ class WC_Shipping {
* Unregister shipping methods.
*/
public function unregister_shipping_methods() {
unset( $this->shipping_methods );
$this->shipping_methods = array();
}
/**
@ -336,30 +336,28 @@ class WC_Shipping {
}
/**
* calculate_shipping_for_package function.
* Calculate shipping rates for a package,
*
* Calculates each shipping methods cost. Rates are cached based on the package to speed up calculations.
* Calculates each shipping methods cost. Rates are stored in the session based on the package hash to avoid re-calculation every page load.
*
* @access public
* @param array $package cart items
* @return array
* @todo Return array() instead of false for consistent return type?
*/
public function calculate_shipping_for_package( $package = array() ) {
if ( ! $this->enabled ) return false;
if ( ! $package ) return false;
if ( ! $this->enabled || ! $package ) {
return false;
}
// Check if we need to recalculate shipping for this package
$package_hash = 'wc_ship_' . md5( json_encode( $package ) . WC_Cache_Helper::get_transient_version( 'shipping' ) );
$status_options = get_option( 'woocommerce_status_options', array() );
$stored_rates = WC()->session->get( 'shipping_for_package' );
if ( false === ( $stored_rates = get_transient( $package_hash ) ) || ! empty( $status_options['shipping_debug_mode'] ) ) {
if ( ! is_array( $stored_rates ) || $package_hash !== $stored_rates['package_hash'] || ! empty( $status_options['shipping_debug_mode'] ) ) {
// Calculate shipping method rates
$package['rates'] = array();
foreach ( $this->load_shipping_methods( $package ) as $shipping_method ) {
if ( $shipping_method->is_available( $package ) && ( empty( $package['ship_via'] ) || in_array( $shipping_method->id, $package['ship_via'] ) ) ) {
// Reset Rates
@ -369,22 +367,24 @@ class WC_Shipping {
$shipping_method->calculate_shipping( $package );
// Place rates in package array
if ( ! empty( $shipping_method->rates ) && is_array( $shipping_method->rates ) )
foreach ( $shipping_method->rates as $rate )
if ( ! empty( $shipping_method->rates ) && is_array( $shipping_method->rates ) ) {
foreach ( $shipping_method->rates as $rate ) {
$package['rates'][ $rate->id ] = $rate;
}
}
}
}
// Filter the calculated rates
$package['rates'] = apply_filters( 'woocommerce_package_rates', $package['rates'], $package );
// Store
set_transient( $package_hash, $package['rates'], 60 * 60 ); // Cached for an hour
// Store in session to avoid recalculation
WC()->session->set( 'shipping_for_package', array(
'package_hash' => $package_hash,
'rates' => $package['rates']
) );
} else {
$package['rates'] = $stored_rates;
$package['rates'] = $stored_rates['rates'];
}
return $package;
@ -395,7 +395,7 @@ class WC_Shipping {
*
* @return array
*/
public function get_packages() {
public function get_packages() {
return $this->packages;
}

View File

@ -452,9 +452,11 @@ class WC_Shortcodes {
return '';
}
$styles = empty( $atts['style'] ) ? '' : ' style="' . esc_attr( $atts['style'] ) . '"';
ob_start();
?>
<p class="product woocommerce add_to_cart_inline <?php echo esc_attr( $atts['class'] ); ?>" style="<?php echo esc_attr( $atts['style'] ); ?>">
<p class="product woocommerce add_to_cart_inline <?php echo esc_attr( $atts['class'] ); ?>"<?php echo $styles; ?>>
<?php if ( 'true' == $atts['show_price'] ) : ?>
<?php echo $product->get_price_html(); ?>

View File

@ -222,13 +222,14 @@ class WC_Tax {
return array();
}
$valid_postcodes = self::_get_wildcard_postcodes( wc_clean( $postcode ) );
$rates_transient_key = 'wc_tax_rates_' . md5( sprintf( '%s+%s+%s+%s+%s', $country, $state, $city, implode( ',', $valid_postcodes), $tax_class ) );
$matched_tax_rates = get_transient( $rates_transient_key );
$postcode = wc_clean( $postcode );
$valid_postcodes = self::_get_wildcard_postcodes( $postcode );
$cache_key = WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'wc_tax_rates_' . md5( sprintf( '%s+%s+%s+%s+%s', $country, $state, $city, $postcode, $tax_class ) );
$matched_tax_rates = wp_cache_get( $cache_key, 'taxes' );
if ( false === $matched_tax_rates ) {
$matched_tax_rates = self::get_matched_tax_rates( $country, $state, $postcode, $city, $tax_class, $valid_postcodes );
set_transient( $rates_transient_key, $matched_tax_rates, WEEK_IN_SECONDS );
wp_cache_set( $cache_key, $matched_tax_rates, 'taxes' );
}
return apply_filters( 'woocommerce_find_rates', $matched_tax_rates, $args );
@ -699,6 +700,8 @@ class WC_Tax {
$wpdb->insert( $wpdb->prefix . 'woocommerce_tax_rates', self::prepare_tax_rate( $tax_rate ) );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
do_action( 'woocommerce_tax_rate_added', $wpdb->insert_id, $tax_rate );
return $wpdb->insert_id;
@ -750,6 +753,8 @@ class WC_Tax {
)
);
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
do_action( 'woocommerce_tax_rate_updated', $tax_rate_id, $tax_rate );
}
@ -769,6 +774,8 @@ class WC_Tax {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d;", $tax_rate_id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $tax_rate_id ) );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
do_action( 'woocommerce_tax_rate_deleted', $tax_rate_id );
}
@ -846,6 +853,8 @@ class WC_Tax {
INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES $sql;
" );
}
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
}
/**

View File

@ -154,11 +154,17 @@ class WC_Tracker {
$wp_data = array();
$memory = wc_let_to_num( WP_MEMORY_LIMIT );
if ( function_exists( 'memory_get_usage' ) ) {
$system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
$memory = max( $memory, $system_memory );
}
$wp_data['memory_limit'] = size_format( $memory );
$wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
$wp_data['locale'] = get_locale();
$wp_data['version'] = get_bloginfo( 'version' );
$wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
$wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
$wp_data['locale'] = get_locale();
$wp_data['version'] = get_bloginfo( 'version' );
$wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
return $wp_data;
}

View File

@ -589,15 +589,26 @@ class WC_Webhook {
* Send a test ping to the delivery URL, sent when the webhook is first created.
*
* @since 2.2
* @return bool|WP_Error
*/
public function deliver_ping() {
$args = array(
'user-agent' => sprintf( 'WooCommerce/%s Hookshot (WordPress/%s)', WC_VERSION, $GLOBALS['wp_version'] ),
'body' => "webhook_id={$this->id}",
);
wp_safe_remote_post( $this->get_delivery_url(), $args );
$test = wp_safe_remote_post( $this->get_delivery_url(), $args );
$response_code = wp_remote_retrieve_response_code( $test );
if ( is_wp_error( $test ) ) {
return new WP_Error( 'error', __( 'Error: Delivery URL cannot be reached: ' . $test->get_error_message() ) );
}
if ( 200 !== $response_code ) {
return new WP_Error( 'error', __( 'Error: Delivery URL returned response code ' . absint( $response_code ) ) );
}
return true;
}
/**
@ -684,8 +695,9 @@ class WC_Webhook {
* @param string $url
*/
public function set_delivery_url( $url ) {
update_post_meta( $this->id, '_delivery_url', esc_url_raw( $url, array( 'http', 'https' ) ) );
if ( update_post_meta( $this->id, '_delivery_url', esc_url_raw( $url, array( 'http', 'https' ) ) ) ) {
update_post_meta( $this->id, '_webhook_pending_delivery', true );
}
}
/**

View File

@ -374,7 +374,7 @@ class WC_CLI_Coupon extends WC_CLI_Command {
*
* @since 2.5.0
*/
public function types( $__, $__ ) {
public function types( $__, $___ ) {
$coupon_types = wc_get_coupon_types();
foreach ( $coupon_types as $type => $label ) {
WP_CLI::line( sprintf( '%s: %s', $label, $type ) );

View File

@ -92,6 +92,7 @@ class WC_CLI_Product_Category extends WC_CLI_Command {
* @since 2.5.0
* @param int $term_id Category term ID
* @return array
* @throws WC_CLI_Exception
*/
protected function get_product_category( $term_id ) {
$term_id = absint( $term_id );

Some files were not shown because too many files have changed in this diff Show More